ant-design-vue
Version:
An enterprise-class UI design language and Vue-based implementation
564 lines (562 loc) • 19.4 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import { createVNode as _createVNode } from "vue";
import classNames from '../../_util/classNames';
import PropTypes, { withUndefined } from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import { hasProp } from '../../_util/props-util';
import Track from './common/Track';
import createSlider from './common/createSlider';
import * as utils from './utils';
import initDefaultProps from '../../_util/props-util/initDefaultProps';
import { defineComponent } from 'vue';
var _trimAlignValue = function trimAlignValue(_ref) {
var value = _ref.value,
handle = _ref.handle,
bounds = _ref.bounds,
props = _ref.props;
var allowCross = props.allowCross,
pushable = props.pushable;
var thershold = Number(pushable);
var valInRange = utils.ensureValueInRange(value, props);
var valNotConflict = valInRange;
if (!allowCross && handle != null && bounds !== undefined) {
if (handle > 0 && valInRange <= bounds[handle - 1] + thershold) {
valNotConflict = bounds[handle - 1] + thershold;
}
if (handle < bounds.length - 1 && valInRange >= bounds[handle + 1] - thershold) {
valNotConflict = bounds[handle + 1] - thershold;
}
}
return utils.ensureValuePrecision(valNotConflict, props);
};
var rangeProps = {
defaultValue: PropTypes.arrayOf(PropTypes.number),
value: PropTypes.arrayOf(PropTypes.number),
count: Number,
pushable: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.number])),
allowCross: {
type: Boolean,
default: undefined
},
disabled: {
type: Boolean,
default: undefined
},
reverse: {
type: Boolean,
default: undefined
},
tabindex: PropTypes.arrayOf(PropTypes.number),
prefixCls: String,
min: Number,
max: Number,
autofocus: {
type: Boolean,
default: undefined
},
ariaLabelGroupForHandles: Array,
ariaLabelledByGroupForHandles: Array,
ariaValueTextFormatterGroupForHandles: Array,
draggableTrack: {
type: Boolean,
default: undefined
}
};
var Range = defineComponent({
compatConfig: {
MODE: 3
},
name: 'Range',
mixins: [BaseMixin],
inheritAttrs: false,
props: initDefaultProps(rangeProps, {
count: 1,
allowCross: true,
pushable: false,
tabindex: [],
draggableTrack: false,
ariaLabelGroupForHandles: [],
ariaLabelledByGroupForHandles: [],
ariaValueTextFormatterGroupForHandles: []
}),
emits: ['beforeChange', 'afterChange', 'change'],
displayName: 'Range',
data: function data() {
var _this = this;
var count = this.count,
min = this.min,
max = this.max;
var initialValue = Array.apply(void 0, _toConsumableArray(Array(count + 1))).map(function () {
return min;
});
var defaultValue = hasProp(this, 'defaultValue') ? this.defaultValue : initialValue;
var value = this.value;
if (value === undefined) {
value = defaultValue;
}
var bounds = value.map(function (v, i) {
return _trimAlignValue({
value: v,
handle: i,
props: _this.$props
});
});
var recent = bounds[0] === max ? 0 : bounds.length - 1;
return {
sHandle: null,
recent: recent,
bounds: bounds
};
},
watch: {
value: {
handler: function handler(val) {
var bounds = this.bounds;
this.setChangeValue(val || bounds);
},
deep: true
},
min: function min() {
var value = this.value;
this.setChangeValue(value || this.bounds);
},
max: function max() {
var value = this.value;
this.setChangeValue(value || this.bounds);
}
},
methods: {
setChangeValue: function setChangeValue(value) {
var _this2 = this;
var bounds = this.bounds;
var nextBounds = value.map(function (v, i) {
return _trimAlignValue({
value: v,
handle: i,
bounds: bounds,
props: _this2.$props
});
});
if (bounds.length === nextBounds.length) {
if (nextBounds.every(function (v, i) {
return v === bounds[i];
})) {
return null;
}
} else {
nextBounds = value.map(function (v, i) {
return _trimAlignValue({
value: v,
handle: i,
props: _this2.$props
});
});
}
this.setState({
bounds: nextBounds
});
if (value.some(function (v) {
return utils.isValueOutOfRange(v, _this2.$props);
})) {
var newValues = value.map(function (v) {
return utils.ensureValueInRange(v, _this2.$props);
});
this.$emit('change', newValues);
}
},
onChange: function onChange(state) {
var isNotControlled = !hasProp(this, 'value');
if (isNotControlled) {
this.setState(state);
} else {
var controlledState = {};
['sHandle', 'recent'].forEach(function (item) {
if (state[item] !== undefined) {
controlledState[item] = state[item];
}
});
if (Object.keys(controlledState).length) {
this.setState(controlledState);
}
}
var data = _objectSpread(_objectSpread({}, this.$data), state);
var changedValue = data.bounds;
this.$emit('change', changedValue);
},
positionGetValue: function positionGetValue(position) {
var bounds = this.getValue();
var value = this.calcValueByPos(position);
var closestBound = this.getClosestBound(value);
var index = this.getBoundNeedMoving(value, closestBound);
var prevValue = bounds[index];
if (value === prevValue) return null;
var nextBounds = _toConsumableArray(bounds);
nextBounds[index] = value;
return nextBounds;
},
onStart: function onStart(position) {
var bounds = this.bounds;
this.$emit('beforeChange', bounds);
var value = this.calcValueByPos(position);
this.startValue = value;
this.startPosition = position;
var closestBound = this.getClosestBound(value);
this.prevMovedHandleIndex = this.getBoundNeedMoving(value, closestBound);
this.setState({
sHandle: this.prevMovedHandleIndex,
recent: this.prevMovedHandleIndex
});
var prevValue = bounds[this.prevMovedHandleIndex];
if (value === prevValue) return;
var nextBounds = _toConsumableArray(bounds);
nextBounds[this.prevMovedHandleIndex] = value;
this.onChange({
bounds: nextBounds
});
},
onEnd: function onEnd(force) {
var sHandle = this.sHandle;
this.removeDocumentEvents();
if (!sHandle) {
this.dragTrack = false;
}
if (sHandle !== null || force) {
this.$emit('afterChange', this.bounds);
}
this.setState({
sHandle: null
});
},
onMove: function onMove(e, position, dragTrack, startBounds) {
utils.pauseEvent(e);
var state = this.$data,
props = this.$props;
var maxValue = props.max || 100;
var minValue = props.min || 0;
if (dragTrack) {
var pos = props.vertical ? -position : position;
pos = props.reverse ? -pos : pos;
var max = maxValue - Math.max.apply(Math, _toConsumableArray(startBounds));
var min = minValue - Math.min.apply(Math, _toConsumableArray(startBounds));
var ratio = Math.min(Math.max(pos / (this.getSliderLength() / 100), min), max);
var nextBounds = startBounds.map(function (v) {
return Math.floor(Math.max(Math.min(v + ratio, maxValue), minValue));
});
if (state.bounds.map(function (c, i) {
return c === nextBounds[i];
}).some(function (c) {
return !c;
})) {
this.onChange({
bounds: nextBounds
});
}
return;
}
var bounds = this.bounds,
sHandle = this.sHandle;
var value = this.calcValueByPos(position);
var oldValue = bounds[sHandle];
if (value === oldValue) return;
this.moveTo(value);
},
onKeyboard: function onKeyboard(e) {
var _this$$props = this.$props,
reverse = _this$$props.reverse,
vertical = _this$$props.vertical;
var valueMutator = utils.getKeyboardValueMutator(e, vertical, reverse);
if (valueMutator) {
utils.pauseEvent(e);
var bounds = this.bounds,
sHandle = this.sHandle;
var oldValue = bounds[sHandle === null ? this.recent : sHandle];
var mutatedValue = valueMutator(oldValue, this.$props);
var value = _trimAlignValue({
value: mutatedValue,
handle: sHandle,
bounds: bounds,
props: this.$props
});
if (value === oldValue) return;
var isFromKeyboardEvent = true;
this.moveTo(value, isFromKeyboardEvent);
}
},
getClosestBound: function getClosestBound(value) {
var bounds = this.bounds;
var closestBound = 0;
for (var i = 1; i < bounds.length - 1; i += 1) {
if (value >= bounds[i]) {
closestBound = i;
}
}
if (Math.abs(bounds[closestBound + 1] - value) < Math.abs(bounds[closestBound] - value)) {
closestBound += 1;
}
return closestBound;
},
getBoundNeedMoving: function getBoundNeedMoving(value, closestBound) {
var bounds = this.bounds,
recent = this.recent;
var boundNeedMoving = closestBound;
var isAtTheSamePoint = bounds[closestBound + 1] === bounds[closestBound];
if (isAtTheSamePoint && bounds[recent] === bounds[closestBound]) {
boundNeedMoving = recent;
}
if (isAtTheSamePoint && value !== bounds[closestBound + 1]) {
boundNeedMoving = value < bounds[closestBound + 1] ? closestBound : closestBound + 1;
}
return boundNeedMoving;
},
getLowerBound: function getLowerBound() {
return this.bounds[0];
},
getUpperBound: function getUpperBound() {
var bounds = this.bounds;
return bounds[bounds.length - 1];
},
/**
* Returns an array of possible slider points, taking into account both
* `marks` and `step`. The result is cached.
*/
getPoints: function getPoints() {
var marks = this.marks,
step = this.step,
min = this.min,
max = this.max;
var cache = this.internalPointsCache;
if (!cache || cache.marks !== marks || cache.step !== step) {
var pointsObject = _objectSpread({}, marks);
if (step !== null) {
for (var point = min; point <= max; point += step) {
pointsObject[point] = point;
}
}
var points = Object.keys(pointsObject).map(parseFloat);
points.sort(function (a, b) {
return a - b;
});
this.internalPointsCache = {
marks: marks,
step: step,
points: points
};
}
return this.internalPointsCache.points;
},
moveTo: function moveTo(value, isFromKeyboardEvent) {
var _this3 = this;
var nextBounds = _toConsumableArray(this.bounds);
var sHandle = this.sHandle,
recent = this.recent;
var handle = sHandle === null ? recent : sHandle;
nextBounds[handle] = value;
var nextHandle = handle;
if (this.$props.pushable !== false) {
this.pushSurroundingHandles(nextBounds, nextHandle);
} else if (this.$props.allowCross) {
nextBounds.sort(function (a, b) {
return a - b;
});
nextHandle = nextBounds.indexOf(value);
}
this.onChange({
recent: nextHandle,
sHandle: nextHandle,
bounds: nextBounds
});
if (isFromKeyboardEvent) {
// known problem: because setState is async,
// so trigger focus will invoke handler's onEnd and another handler's onStart too early,
// cause onBeforeChange and onAfterChange receive wrong value.
// here use setState callback to hack,but not elegant
this.$emit('afterChange', nextBounds);
this.setState({}, function () {
_this3.handlesRefs[nextHandle].focus();
});
this.onEnd();
}
},
pushSurroundingHandles: function pushSurroundingHandles(bounds, handle) {
var value = bounds[handle];
var pushable = this.pushable;
var threshold = Number(pushable);
var direction = 0;
if (bounds[handle + 1] - value < threshold) {
direction = +1; // push to right
}
if (value - bounds[handle - 1] < threshold) {
direction = -1; // push to left
}
if (direction === 0) {
return;
}
var nextHandle = handle + direction;
var diffToNext = direction * (bounds[nextHandle] - value);
if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
// revert to original value if pushing is impossible
bounds[handle] = bounds[nextHandle] - direction * threshold;
}
},
pushHandle: function pushHandle(bounds, handle, direction, amount) {
var originalValue = bounds[handle];
var currentValue = bounds[handle];
while (direction * (currentValue - originalValue) < amount) {
if (!this.pushHandleOnePoint(bounds, handle, direction)) {
// can't push handle enough to create the needed `amount` gap, so we
// revert its position to the original value
bounds[handle] = originalValue;
return false;
}
currentValue = bounds[handle];
}
// the handle was pushed enough to create the needed `amount` gap
return true;
},
pushHandleOnePoint: function pushHandleOnePoint(bounds, handle, direction) {
var points = this.getPoints();
var pointIndex = points.indexOf(bounds[handle]);
var nextPointIndex = pointIndex + direction;
if (nextPointIndex >= points.length || nextPointIndex < 0) {
// reached the minimum or maximum available point, can't push anymore
return false;
}
var nextHandle = handle + direction;
var nextValue = points[nextPointIndex];
var pushable = this.pushable;
var threshold = Number(pushable);
var diffToNext = direction * (bounds[nextHandle] - nextValue);
if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
// couldn't push next handle, so we won't push this one either
return false;
}
// push the handle
bounds[handle] = nextValue;
return true;
},
trimAlignValue: function trimAlignValue(value) {
var sHandle = this.sHandle,
bounds = this.bounds;
return _trimAlignValue({
value: value,
handle: sHandle,
bounds: bounds,
props: this.$props
});
},
ensureValueNotConflict: function ensureValueNotConflict(handle, val, _ref2) {
var allowCross = _ref2.allowCross,
thershold = _ref2.pushable;
var state = this.$data || {};
var bounds = state.bounds;
handle = handle === undefined ? state.sHandle : handle;
thershold = Number(thershold);
/* eslint-disable eqeqeq */
if (!allowCross && handle != null && bounds !== undefined) {
if (handle > 0 && val <= bounds[handle - 1] + thershold) {
return bounds[handle - 1] + thershold;
}
if (handle < bounds.length - 1 && val >= bounds[handle + 1] - thershold) {
return bounds[handle + 1] - thershold;
}
}
/* eslint-enable eqeqeq */
return val;
},
getTrack: function getTrack(_ref3) {
var bounds = _ref3.bounds,
prefixCls = _ref3.prefixCls,
reverse = _ref3.reverse,
vertical = _ref3.vertical,
included = _ref3.included,
offsets = _ref3.offsets,
trackStyle = _ref3.trackStyle;
return bounds.slice(0, -1).map(function (_, index) {
var _classNames;
var i = index + 1;
var trackClassName = classNames((_classNames = {}, _defineProperty(_classNames, "".concat(prefixCls, "-track"), true), _defineProperty(_classNames, "".concat(prefixCls, "-track-").concat(i), true), _classNames));
return _createVNode(Track, {
"class": trackClassName,
"vertical": vertical,
"reverse": reverse,
"included": included,
"offset": offsets[i - 1],
"length": offsets[i] - offsets[i - 1],
"style": trackStyle[index],
"key": i
}, null);
});
},
renderSlider: function renderSlider() {
var _this4 = this;
var sHandle = this.sHandle,
bounds = this.bounds,
prefixCls = this.prefixCls,
vertical = this.vertical,
included = this.included,
disabled = this.disabled,
min = this.min,
max = this.max,
reverse = this.reverse,
handle = this.handle,
defaultHandle = this.defaultHandle,
trackStyle = this.trackStyle,
handleStyle = this.handleStyle,
tabindex = this.tabindex,
ariaLabelGroupForHandles = this.ariaLabelGroupForHandles,
ariaLabelledByGroupForHandles = this.ariaLabelledByGroupForHandles,
ariaValueTextFormatterGroupForHandles = this.ariaValueTextFormatterGroupForHandles;
var handleGenerator = handle || defaultHandle;
var offsets = bounds.map(function (v) {
return _this4.calcOffset(v);
});
var handleClassName = "".concat(prefixCls, "-handle");
var handles = bounds.map(function (v, i) {
var _classNames2;
var mergedTabIndex = tabindex[i] || 0;
if (disabled || tabindex[i] === null) {
mergedTabIndex = null;
}
var dragging = sHandle === i;
return handleGenerator({
class: classNames((_classNames2 = {}, _defineProperty(_classNames2, handleClassName, true), _defineProperty(_classNames2, "".concat(handleClassName, "-").concat(i + 1), true), _defineProperty(_classNames2, "".concat(handleClassName, "-dragging"), dragging), _classNames2)),
prefixCls: prefixCls,
vertical: vertical,
dragging: dragging,
offset: offsets[i],
value: v,
index: i,
tabindex: mergedTabIndex,
min: min,
max: max,
reverse: reverse,
disabled: disabled,
style: handleStyle[i],
ref: function ref(h) {
return _this4.saveHandle(i, h);
},
onFocus: _this4.onFocus,
onBlur: _this4.onBlur,
ariaLabel: ariaLabelGroupForHandles[i],
ariaLabelledBy: ariaLabelledByGroupForHandles[i],
ariaValueTextFormatter: ariaValueTextFormatterGroupForHandles[i]
});
});
return {
tracks: this.getTrack({
bounds: bounds,
prefixCls: prefixCls,
reverse: reverse,
vertical: vertical,
included: included,
offsets: offsets,
trackStyle: trackStyle
}),
handles: handles
};
}
}
});
export default createSlider(Range);