UNPKG

@alifd/next

Version:

A configurable component library for web built on React.

853 lines (731 loc) 29.1 kB
'use strict'; exports.__esModule = true; var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _class, _temp; var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactLifecyclesCompat = require('react-lifecycles-compat'); var _util = require('../../util'); var _balloon = require('../../balloon'); var _balloon2 = _interopRequireDefault(_balloon); var _utils = require('../utils'); var _scale = require('./scale'); var _scale2 = _interopRequireDefault(_scale); var _track = require('./track'); var _track2 = _interopRequireDefault(_track); var _selected = require('./selected'); var _selected2 = _interopRequireDefault(_selected); var _mark = require('./mark'); var _mark2 = _interopRequireDefault(_mark); var _slider = require('./slider'); var _slider2 = _interopRequireDefault(_slider); var _fixedSlider = require('./fixedSlider'); var _fixedSlider2 = _interopRequireDefault(_fixedSlider); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Tooltip = _balloon2.default.Tooltip; var noop = _util.func.noop, bindCtx = _util.func.bindCtx; var pickOthers = _util.obj.pickOthers; function _isMultiple(slider, isFixedWidth) { return isFixedWidth || slider === 'double'; } function LowerSlider(props) { var hasTip = props.hasTip, value = props.value, tipRender = props.tipRender, slider = props.slider, tooltipVisible = props.tooltipVisible, onTooltipVisibleChange = props.onTooltipVisibleChange, tooltipAnimation = props.tooltipAnimation; if (_isMultiple(slider)) { return hasTip ? _react2.default.createElement( Tooltip, { popupContainer: function popupContainer(target) { return target.parentNode; }, popupProps: { visible: tooltipVisible, onVisibleChange: onTooltipVisibleChange, animation: tooltipAnimation, needAdjust: false }, trigger: (0, _slider2.default)((0, _extends3.default)({}, props, { value: value[0] })), align: 't' }, tipRender('' + value[0]) ) : (0, _slider2.default)((0, _extends3.default)({}, props, { value: value[0] })); } return null; } LowerSlider.propTypes = { hasTip: _propTypes2.default.bool, tooltipVisible: _propTypes2.default.bool, onTooltipVisibleChange: _propTypes2.default.func, tooltipAnimation: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.object]), value: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number)]), tipRender: _propTypes2.default.func, slider: _propTypes2.default.oneOf(['single', 'double']) }; function UpperSlider(props) { var newprop = (0, _extends3.default)({}, props); var hasTip = newprop.hasTip, value = newprop.value, tipRender = newprop.tipRender, slider = newprop.slider, tooltipVisible = newprop.tooltipVisible, onTooltipVisibleChange = newprop.onTooltipVisibleChange, tooltipAnimation = newprop.tooltipAnimation; if (_isMultiple(slider)) { delete newprop.onKeyDown; return hasTip ? _react2.default.createElement( Tooltip, { popupContainer: function popupContainer(target) { return target.parentNode; }, popupProps: { visible: tooltipVisible, onVisibleChange: onTooltipVisibleChange, animation: tooltipAnimation, needAdjust: false }, trigger: (0, _slider2.default)((0, _extends3.default)({}, newprop, { value: value[1] })), align: 't' }, tipRender(value[1]) ) : (0, _slider2.default)((0, _extends3.default)({}, newprop, { value: value[1] })); } return hasTip ? _react2.default.createElement( Tooltip, { popupContainer: function popupContainer(target) { return target.parentNode; }, popupProps: { visible: tooltipVisible, onVisibleChange: onTooltipVisibleChange, animation: tooltipAnimation, needAdjust: false }, animation: { in: 'fadeInUp', out: 'fadeOutDown' }, trigger: (0, _slider2.default)(newprop), align: 't' }, tipRender(value) ) : (0, _slider2.default)(newprop); } UpperSlider.propTypes = { hasTip: _propTypes2.default.bool, tooltipVisible: _propTypes2.default.bool, onTooltipVisibleChange: _propTypes2.default.func, tooltipAnimation: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.object]), value: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number)]), tipRender: _propTypes2.default.func, slider: _propTypes2.default.oneOf(['single', 'double']) }; function pauseEvent(e) { e.stopPropagation(); e.preventDefault(); } /** Range */ var Range = (_temp = _class = function (_React$Component) { (0, _inherits3.default)(Range, _React$Component); function Range(props) { (0, _classCallCheck3.default)(this, Range); var _this = (0, _possibleConstructorReturn3.default)(this, _React$Component.call(this, props)); var min = props.min; var initialValue = _isMultiple(props.slider) ? [min, min] : min; var defaultValue = 'defaultValue' in props ? props.defaultValue : initialValue; var value = props.value !== undefined ? props.value : defaultValue; _this.state = { value: value, tempValue: value, hasMovingClass: false, lowerTooltipVisible: false, upperTooltipVisible: false, tooltipAnimation: true }; bindCtx(_this, ['handleLowerTooltipVisibleChange', 'handleUpperTooltipVisibleChange', 'onKeyDown']); return _this; } Range.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) { if ('value' in props) { var min = props.min, slider = props.slider, value = props.value; var hasMovingClass = state.hasMovingClass; var newState = { value: value }; if (value === undefined) { newState.value = _isMultiple(slider) ? [min, min] : min; } if (!hasMovingClass) { newState.tempValue = newState.value; } return newState; } return null; }; Range.prototype._marksToScales = function _marksToScales(marks) { var result = []; if (Object.prototype.toString.call(marks) === '[object Object]') { for (var key in marks) { if (Object.hasOwnProperty.call(marks, key)) { result.push(parseInt(key)); } } } else { result = marks; } return result; }; Range.prototype._calcScales = function _calcScales() { var _props = this.props, min = _props.min, max = _props.max, marks = _props.marks; var scales = this._marksToScales(marks); if (scales !== false) { if (Array.isArray(scales)) { return scales; } else { var pace = (max - min) / scales; var result = []; result.push(min); for (var i = 1; i < scales; i++) { result.push(min + i * pace); } result.push(max); return result; } } else { return []; } }; Range.prototype._calcMarks = function _calcMarks() { var _props2 = this.props, min = _props2.min, max = _props2.max, marks = _props2.marks; var result = {}; if (Array.isArray(marks)) { marks.forEach(function (m) { result[m] = m.toString(); }); } else if (typeof marks === 'number') { var pace = (max - min) / marks; result[min] = min; for (var i = 1; i < marks; i++) { var mark = min + i * pace; var precision = (0, _utils.getPrecision)(mark); if (precision > 2) { precision = 2; } mark = mark.toFixed(precision); result[mark] = mark; } result[max] = max; } else { result = marks; } return result; }; Range.prototype._onMouseDown = function _onMouseDown(e) { if (e.button === 0) { this._start(e.pageX); this._addDocumentMouseEvents(); pauseEvent(e); } }; Range.prototype._onTouchStart = function _onTouchStart(e) { this._start(e.targetTouches[0].pageX); this._addDocumentTouchEvents(); e.stopPropagation(); // preventDefault() will be ignored: https://www.chromestatus.com/features/5093566007214080 }; Range.prototype.onKeyDown = function onKeyDown(e) { if (this.props.disabled) return; if (e.keyCode === _util.KEYCODE.LEFT_ARROW || e.keyCode === _util.KEYCODE.RIGHT_ARROW) { e.stopPropagation(); e.preventDefault(); var newValue = void 0; if (e.keyCode === _util.KEYCODE.LEFT_ARROW) { newValue = this.state.value - this.props.step; } else { newValue = this.state.value + this.props.step; } if (newValue > this.props.max) { newValue = this.props.max; } if (newValue < this.props.min) { newValue = this.props.min; } if (newValue !== this.state.value) { this.setState({ value: newValue }); this.props.onChange(newValue); } } }; Range.prototype._start = function _start(position) { this.setState({ hasMovingClass: true }); var tempValue = this.state.tempValue; var range = this.dom; var start = _util.dom.getOffset(range).left; // used in unit test var width = range.clientWidth; if (!width) { if (range.style.width) { var index = range.style.width.indexOf('px'); if (index !== -1) { width = Number(range.style.width.slice(0, index)); } } } this._moving = { start: start, end: start + width, startValue: tempValue }; // change on start this._onProcess(position, true); }; Range.prototype._end = function _end() { var startValue = this._moving.startValue; var _state = this.state, tempValue = _state.tempValue, value = _state.value; this._moving = null; this._removeDocumentEvents(); this.setState({ hasMovingClass: false, lowerTooltipVisible: false, upperTooltipVisible: false, tooltipAnimation: true }); if (!(0, _utils.isEqual)(tempValue, startValue)) { // Not Controlled if (!('value' in this.props)) { this.setState({ value: tempValue }); } else { this.setState({ // tooltipVisible: false, tempValue: value, value: value }); } this.props.onChange(tempValue); } }; Range.prototype._move = function _move(e) { var position = e.type === 'mousemove' ? e.pageX : e.targetTouches[0].pageX; this._onProcess(position); }; Range.prototype._onProcess = function _onProcess(position, start) { var tempValue = this.state.tempValue; var current = this._positionToCurrent(position); //current 为当前click的value if (this.isFixedWidth) { if (start) { this.lastPosition = current; } } else if (start) { this.lastPosition = current; if (_isMultiple(this.props.slider)) { this._moving.dragging = (0, _utils.getDragging)(current, tempValue); } else { this._moving.dragging = 'upper'; } this.setState({ lowerTooltipVisible: this._moving.dragging === 'lower', upperTooltipVisible: this._moving.dragging === 'upper', tooltipAnimation: false }); } else if (this.oldDragging === 'lower' && this._moving.dragging === 'upper') { this.setState({ upperTooltipVisible: true, lowerTooltipVisible: false }); } else if (this.oldDragging === 'upper' && this._moving.dragging === 'lower') { this.setState({ upperTooltipVisible: false, lowerTooltipVisible: true }); } this.oldDragging = this._moving.dragging; var nextValue = this._currentToValue(current, tempValue, this.lastPosition, this.isFixedWidth); //计算range的新value,可能是数组,可能是单个值 this.lastPosition = current; if (!(0, _utils.isEqual)(nextValue, tempValue)) { this.setState({ tempValue: nextValue }); this.props.onProcess(nextValue); } }; Range.prototype._addDocumentMouseEvents = function _addDocumentMouseEvents() { this._onMouseMoveListener = _util.events.on(document, 'mousemove', this._move.bind(this)); this._onMouseUpListener = _util.events.on(document, 'mouseup', this._end.bind(this)); }; Range.prototype._addDocumentTouchEvents = function _addDocumentTouchEvents() { this._onTouchMoveListener = _util.events.on(document, 'touchmove', this._move.bind(this)); this._onTouchEndListener = _util.events.on(document, 'touchend', this._end.bind(this)); }; Range.prototype._removeDocumentEvents = function _removeDocumentEvents() { if (this._onMouseMoveListener) { this._onMouseMoveListener.off(); this._onMouseMoveListener = null; } if (this._onMouseUpListener) { this._onMouseUpListener.off(); this._onMouseUpListener = null; } if (this._onTouchMoveListener) { this._onTouchMoveListener.off(); this._onTouchMoveListener = null; } if (this._onTouchEndListener) { this._onTouchEndListener.off(); this._onTouchEndListener = null; } }; // position => current (value type) Range.prototype._positionToCurrent = function _positionToCurrent(position) { var _moving = this._moving, start = _moving.start, end = _moving.end; var _props3 = this.props, step = _props3.step, min = _props3.min, max = _props3.max, rtl = _props3.rtl; if (position < start) { position = start; } else if (position > end) { position = end; } var percent = (0, _utils.getPercent)(start, end, position); percent = rtl ? 100 - percent : percent; // reset by step var newValue = parseFloat((Math.round(percent / 100 * (max - min) / step) * step).toFixed((0, _utils.getPrecision)(step))); var currentValue = (min + newValue).toFixed((0, _utils.getPrecision)(step)); return Number(currentValue); }; Range.prototype._currentToValue = function _currentToValue(current, preValue, lastPosition, isFixedWidth) { var dragging = this._moving.dragging; var _props4 = this.props, min = _props4.min, max = _props4.max; if (!_isMultiple(this.props.slider, isFixedWidth)) { return current; } else { var result = void 0; var precision = (0, _utils.getPrecision)(this.props.step); var diff = current - lastPosition; var newLeft = +(+preValue[0] + diff).toFixed(precision); var newRight = +(+preValue[1] + diff).toFixed(precision); var newMaxLeft = +(max - preValue[1] + preValue[0]).toFixed(precision); var newMinRight = +(min + preValue[1] - preValue[0]).toFixed(precision); if (isFixedWidth) { if (newLeft < min) { result = [min, newMinRight]; } else if (newRight > max) { result = [newMaxLeft, max]; } else { result = [newLeft, newRight]; } } else if (dragging === 'lower') { if (current > preValue[1]) { result = [preValue[1], current]; this._moving.dragging = 'upper'; } else { result = [current, preValue[1]]; } } else if (dragging === 'upper') { if (current < preValue[0]) { result = [current, preValue[0]]; this._moving.dragging = 'lower'; } else { result = [preValue[0], current]; } } return result; } }; Range.prototype.handleLowerTooltipVisibleChange = function handleLowerTooltipVisibleChange(visible) { if (this.state.hasMovingClass) { return; } this.setState({ lowerTooltipVisible: visible }); }; Range.prototype.handleUpperTooltipVisibleChange = function handleUpperTooltipVisibleChange(visible) { if (this.state.hasMovingClass) { return; } this.setState({ upperTooltipVisible: visible }); }; Range.prototype.render = function render() { var _classNames, _this2 = this; var value = this._moving ? this.state.tempValue : this.state.value; var _props5 = this.props, prefix = _props5.prefix, min = _props5.min, max = _props5.max, disabled = _props5.disabled, style = _props5.style, id = _props5.id, slider = _props5.slider, reverse = _props5.reverse, className = _props5.className, marks = _props5.marks, marksPosition = _props5.marksPosition, hasTip = _props5.hasTip, tipRender = _props5.tipRender, fixedWidth = _props5.fixedWidth, defaultValue = _props5.defaultValue, tooltipVisible = _props5.tooltipVisible, rtl = _props5.rtl, isPreview = _props5.isPreview, renderPreview = _props5.renderPreview; var others = pickOthers(Object.keys(Range.propTypes), this.props); var classes = (0, _classnames2.default)((_classNames = {}, _classNames[prefix + 'range'] = true, _classNames.disabled = disabled, _classNames[className] = className, _classNames)); if (Array.isArray(value)) { value.forEach(function (item, index) { if (item > max) { value[index] = max; } }); } else if (value > max) { value = max; } var commonProps = { prefix: prefix, min: min, max: max, value: value, reverse: reverse, slider: slider, hasTip: hasTip, tipRender: tipRender, marksPosition: marksPosition, tooltipVisible: tooltipVisible, hasMovingClass: this.state.hasMovingClass, disabled: disabled, rtl: rtl }; this.isFixedWidth = fixedWidth && (value ? Array.isArray(value) : defaultValue ? Array.isArray(defaultValue) : false); if (isPreview) { var previewCls = (0, _classnames2.default)(className, prefix + 'form-preview'); if ('renderPreview' in this.props) { return _react2.default.createElement( 'div', (0, _extends3.default)({ id: id, dir: rtl ? 'rtl' : 'ltr' }, others, { className: previewCls }), renderPreview(value, this.props) ); } return _react2.default.createElement( 'p', (0, _extends3.default)({ id: id, dir: rtl ? 'rtl' : 'ltr' }, others, { className: previewCls }), Array.isArray(value) ? value.join('~') : value ); } return _react2.default.createElement( 'div', (0, _extends3.default)({ ref: function ref(dom) { _this2.dom = dom; } }, others, { style: style, className: classes, id: id, dir: rtl ? 'rtl' : 'ltr', onMouseDown: disabled ? noop : this._onMouseDown.bind(this), onTouchStart: disabled ? noop : this._onTouchStart.bind(this) }), marks !== false && marksPosition === 'above' ? _react2.default.createElement(_mark2.default, (0, _extends3.default)({}, commonProps, { marks: this._calcMarks() })) : null, _react2.default.createElement( 'div', { className: prefix + 'range-inner' }, _react2.default.createElement(_scale2.default, (0, _extends3.default)({}, commonProps, { scales: this._calcScales() })), _react2.default.createElement(_track2.default, commonProps), this.isFixedWidth ? _react2.default.createElement(_fixedSlider2.default, commonProps) : _react2.default.createElement( 'div', null, _react2.default.createElement(_selected2.default, commonProps), _react2.default.createElement(LowerSlider, (0, _extends3.default)({}, commonProps, { hasMovingClass: this.state.hasMovingClass && this._moving && this._moving.dragging === 'lower', tooltipVisible: tooltipVisible || this.state.lowerTooltipVisible, onTooltipVisibleChange: this.handleLowerTooltipVisibleChange, tooltipAnimation: this.state.tooltipAnimation ? { in: 'expandInUp', out: 'expandOutDown' } : false })), _react2.default.createElement(UpperSlider, (0, _extends3.default)({}, commonProps, { onKeyDown: this.onKeyDown, hasMovingClass: this.state.hasMovingClass && this._moving && this._moving.dragging === 'upper', tooltipVisible: tooltipVisible || this.state.upperTooltipVisible, onTooltipVisibleChange: this.handleUpperTooltipVisibleChange, tooltipAnimation: this.state.tooltipAnimation ? { in: 'expandInUp', out: 'expandOutDown' } : false })) ) ), marks !== false && marksPosition === 'below' ? _react2.default.createElement(_mark2.default, (0, _extends3.default)({}, commonProps, { marks: this._calcMarks() })) : null ); }; return Range; }(_react2.default.Component), _class.contextTypes = { prefix: _propTypes2.default.string }, _class.propTypes = { /** * 样式类名的品牌前缀 */ prefix: _propTypes2.default.string, /** * 自定义类名 */ className: _propTypes2.default.string, /** * 自定义内敛样式 */ style: _propTypes2.default.object, /** * 滑块个数 * @enumdesc 单个, 两个 */ slider: _propTypes2.default.oneOf(['single', 'double']), /** * 最小值 */ min: _propTypes2.default.number, /** * 最大值 */ max: _propTypes2.default.number, /** * 步长,取值必须大于 0,并且可被 (max - min) 整除。 */ step: _propTypes2.default.number, /** * 设置当前取值。当 `slider` 为 `single` 时,使用 `Number`,否则用 `[Number, Number]` */ value: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number)]), tempValue: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number)]), /** * 设置初始取值。当 `slider` 为 `single` 时,使用 `Number`,否则用 `[Number, Number]` */ defaultValue: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number)]), /** * 刻度数值显示逻辑(false 代表不显示,array 枚举显示的值,number 代表按 number 平分,object 表示按 key 划分,value 值显示) */ marks: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.number, _propTypes2.default.arrayOf(_propTypes2.default.number), _propTypes2.default.object]), /** * marks显示在上方('above')or下方('below') */ marksPosition: _propTypes2.default.oneOf(['above', 'below']), /** * 值为 `true` 时,滑块为禁用状态 */ disabled: _propTypes2.default.bool, /** * 当 Range 的值发生改变后,会触发 onChange 事件,并把改变后的值作为参数传入, 如果设置了value, 要配合此函数做受控使用 * @param {String/number} value */ onChange: _propTypes2.default.func, /** * 滑块拖动的时候触发的事件,不建议在这里setState, 一般情况下不需要用, 滑动时有特殊需求时使用 * @param {String/number} value */ onProcess: _propTypes2.default.func, /** * 是否显示 tip */ hasTip: _propTypes2.default.bool, /** * 自定义 tip 显示内容 * @param {Number|String} value 值 * @return {ReactNode} 显示内容 */ tipRender: _propTypes2.default.func, id: _propTypes2.default.string, /** * 选中态反转 */ reverse: _propTypes2.default.bool, /** * 是否pure render */ pure: _propTypes2.default.bool, /** * 是否为拖动线段类型,默认slider为double, defaultValue必传且指定区间 */ fixedWidth: _propTypes2.default.bool, /** * tooltip是否默认展示 */ tooltipVisible: _propTypes2.default.bool, /** * 是否已rtl模式展示 */ rtl: _propTypes2.default.bool, /** * 是否为预览态 */ isPreview: _propTypes2.default.bool, /** * 预览态模式下渲染的内容 * @param {number} value 评分值 */ renderPreview: _propTypes2.default.func }, _class.defaultProps = { prefix: 'next-', slider: 'single', min: 0, max: 100, step: 1, marks: false, disabled: false, fixedWidth: false, tooltipVisible: false, hasTip: true, onChange: noop, onProcess: noop, tipRender: function tipRender(value) { return value; }, reverse: false, pure: false, marksPosition: 'above', rtl: false, isPreview: false }, _temp); Range.displayName = 'Range'; exports.default = (0, _reactLifecyclesCompat.polyfill)(Range); module.exports = exports['default'];