add vc-slider v0.1
parent
847bed5bca
commit
263dd3a520
|
@ -1,74 +1,80 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
|
||||||
|
|
||||||
export default class Handle extends React.Component {
|
import classNames from 'classnames'
|
||||||
state = {
|
import PropTypes from '../../../_util/vue-types'
|
||||||
clickFocused: false,
|
import addEventListener from '../../../_util/Dom/addEventListener'
|
||||||
}
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
|
|
||||||
componentDidMount() {
|
export default {
|
||||||
// mouseup won't trigger if mouse moved out of handle,
|
mixins: [BaseMixin],
|
||||||
// so we listen on document here.
|
props: {
|
||||||
this.onMouseUpListener = addEventListener(document, 'mouseup', this.handleMouseUp);
|
prefixCls: PropTypes.string,
|
||||||
}
|
vertical: PropTypes.bool,
|
||||||
|
offset: PropTypes.number,
|
||||||
componentWillUnmount() {
|
disabled: PropTypes.bool,
|
||||||
if (this.onMouseUpListener) {
|
min: PropTypes.number,
|
||||||
this.onMouseUpListener.remove();
|
max: PropTypes.number,
|
||||||
|
value: PropTypes.number,
|
||||||
|
tabIndex: PropTypes.number,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
clickFocused: false,
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
mounted () {
|
||||||
setClickFocus(focused) {
|
this.$nextTick(() => {
|
||||||
this.setState({ clickFocused: focused });
|
this.onMouseUpListener = addEventListener(document, 'mouseup', this.handleMouseUp)
|
||||||
}
|
})
|
||||||
|
},
|
||||||
handleMouseUp = () => {
|
beforeDestroy () {
|
||||||
if (document.activeElement === this.handle) {
|
this.$nextTick(() => {
|
||||||
this.setClickFocus(true);
|
if (this.onMouseUpListener) {
|
||||||
}
|
this.onMouseUpListener.remove()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
handleBlur = () => {
|
},
|
||||||
this.setClickFocus(false);
|
methods: {
|
||||||
}
|
setClickFocus (focused) {
|
||||||
|
this.setState({ clickFocused: focused })
|
||||||
handleKeyDown = () => {
|
},
|
||||||
this.setClickFocus(false);
|
handleMouseUp () {
|
||||||
}
|
if (document.activeElement === this.$refs.handle) {
|
||||||
|
this.setClickFocus(true)
|
||||||
clickFocus() {
|
}
|
||||||
this.setClickFocus(true);
|
},
|
||||||
this.focus();
|
handleBlur () {
|
||||||
}
|
this.setClickFocus(false)
|
||||||
|
},
|
||||||
focus() {
|
handleKeyDown () {
|
||||||
this.handle.focus();
|
this.setClickFocus(false)
|
||||||
}
|
},
|
||||||
|
clickFocus () {
|
||||||
blur() {
|
this.setClickFocus(true)
|
||||||
this.handle.blur();
|
this.focus()
|
||||||
}
|
},
|
||||||
|
focus () {
|
||||||
render() {
|
this.$refs.handle.focus()
|
||||||
|
},
|
||||||
|
blur () {
|
||||||
|
this.$refs.handle.blur()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render () {
|
||||||
const {
|
const {
|
||||||
prefixCls, vertical, offset, style, disabled, min, max, value, tabIndex, ...restProps,
|
prefixCls, vertical, offset, disabled, min, max, value, tabIndex, ...restProps
|
||||||
} = this.props;
|
} = this.$props
|
||||||
|
|
||||||
const className = classNames(
|
const className = classNames(
|
||||||
this.props.className,
|
|
||||||
{
|
{
|
||||||
[`${prefixCls}-handle-click-focused`]: this.state.clickFocused,
|
[`${prefixCls}-handle-click-focused`]: this.clickFocused,
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
const postionStyle = vertical ? { bottom: `${offset}%` } : { left: `${offset}%` };
|
const postionStyle = vertical ? { bottom: `${offset}%` } : { left: `${offset}%` }
|
||||||
const elStyle = {
|
const elStyle = {
|
||||||
...style,
|
|
||||||
...postionStyle,
|
...postionStyle,
|
||||||
};
|
}
|
||||||
let ariaProps = {};
|
let ariaProps = {}
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
ariaProps = {
|
ariaProps = {
|
||||||
...ariaProps,
|
...ariaProps,
|
||||||
|
@ -76,34 +82,21 @@ export default class Handle extends React.Component {
|
||||||
'aria-valuemax': max,
|
'aria-valuemax': max,
|
||||||
'aria-valuenow': value,
|
'aria-valuenow': value,
|
||||||
'aria-disabled': !!disabled,
|
'aria-disabled': !!disabled,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={node => (this.handle = node)}
|
ref='handle'
|
||||||
role="slider"
|
role='slider'
|
||||||
tabIndex= {disabled ? null : (tabIndex || 0)}
|
tabIndex= {disabled ? null : (tabIndex || 0)}
|
||||||
{...ariaProps}
|
{...ariaProps}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
className={className}
|
class={className}
|
||||||
style={elStyle}
|
style={elStyle}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeydown={this.handleKeyDown}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle.propTypes = {
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
className: PropTypes.string,
|
|
||||||
vertical: PropTypes.bool,
|
|
||||||
offset: PropTypes.number,
|
|
||||||
style: PropTypes.object,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
min: PropTypes.number,
|
|
||||||
max: PropTypes.number,
|
|
||||||
value: PropTypes.number,
|
|
||||||
tabIndex: PropTypes.number,
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,327 +1,308 @@
|
||||||
/* eslint-disable react/prop-types */
|
import classNames from 'classnames'
|
||||||
import React from 'react';
|
import PropTypes from '../../../_util/vue-types'
|
||||||
import PropTypes from 'prop-types';
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
import classNames from 'classnames';
|
import { initDefaultProps, hasProp } from '../../../_util/props-util'
|
||||||
import shallowEqual from 'shallowequal';
|
import Track from './common/Track'
|
||||||
import Track from './common/Track';
|
import createSlider from './common/createSlider'
|
||||||
import createSlider from './common/createSlider';
|
import * as utils from './utils'
|
||||||
import * as utils from './utils';
|
|
||||||
|
|
||||||
class Range extends React.Component {
|
const rangeProps = {
|
||||||
static displayName = 'Range';
|
defaultValue: PropTypes.arrayOf(PropTypes.number),
|
||||||
static propTypes = {
|
value: PropTypes.arrayOf(PropTypes.number),
|
||||||
defaultValue: PropTypes.arrayOf(PropTypes.number),
|
count: PropTypes.number,
|
||||||
value: PropTypes.arrayOf(PropTypes.number),
|
pushable: PropTypes.oneOfType([
|
||||||
count: PropTypes.number,
|
PropTypes.bool,
|
||||||
pushable: PropTypes.oneOfType([
|
PropTypes.number,
|
||||||
PropTypes.bool,
|
]),
|
||||||
PropTypes.number,
|
allowCross: PropTypes.bool,
|
||||||
]),
|
disabled: PropTypes.bool,
|
||||||
allowCross: PropTypes.bool,
|
tabIndex: PropTypes.arrayOf(PropTypes.number),
|
||||||
disabled: PropTypes.bool,
|
}
|
||||||
tabIndex: PropTypes.arrayOf(PropTypes.number),
|
const Range = {
|
||||||
};
|
displayName: 'Range',
|
||||||
|
mixins: [BaseMixin],
|
||||||
static defaultProps = {
|
props: initDefaultProps(rangeProps, {
|
||||||
count: 1,
|
count: 1,
|
||||||
allowCross: true,
|
allowCross: true,
|
||||||
pushable: false,
|
pushable: false,
|
||||||
tabIndex: [],
|
tabIndex: [],
|
||||||
};
|
}),
|
||||||
|
data () {
|
||||||
constructor(props) {
|
const { count, min, max } = this
|
||||||
super(props);
|
|
||||||
|
|
||||||
const { count, min, max } = props;
|
|
||||||
const initialValue = Array.apply(null, Array(count + 1))
|
const initialValue = Array.apply(null, Array(count + 1))
|
||||||
.map(() => min);
|
.map(() => min)
|
||||||
const defaultValue = 'defaultValue' in props ?
|
const defaultValue = hasProp(this, 'defaultValue') ? this.defaultValue : initialValue
|
||||||
props.defaultValue : initialValue;
|
let { value } = this
|
||||||
const value = props.value !== undefined ?
|
if (value === undefined) {
|
||||||
props.value : defaultValue;
|
value = defaultValue
|
||||||
const bounds = value.map((v, i) => this.trimAlignValue(v, i));
|
}
|
||||||
const recent = bounds[0] === max ? 0 : bounds.length - 1;
|
const bounds = value.map((v, i) => this.trimAlignValue(v, i))
|
||||||
|
const recent = bounds[0] === max ? 0 : bounds.length - 1
|
||||||
this.state = {
|
return {
|
||||||
handle: null,
|
handle: null,
|
||||||
recent,
|
recent,
|
||||||
bounds,
|
bounds,
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
if (!('value' in nextProps || 'min' in nextProps || 'max' in nextProps)) return;
|
|
||||||
if (this.props.min === nextProps.min &&
|
|
||||||
this.props.max === nextProps.max &&
|
|
||||||
shallowEqual(this.props.value, nextProps.value)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler (val) {
|
||||||
|
const { min, max } = this
|
||||||
|
this.setChangeValue(val, min, max)
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
min (val) {
|
||||||
|
const { bounds, max } = this
|
||||||
|
this.setChangeValue(bounds, val, max)
|
||||||
|
},
|
||||||
|
max (val) {
|
||||||
|
const { bounds, min } = this
|
||||||
|
this.setChangeValue(bounds, min, val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setChangeValue (value, min, max) {
|
||||||
|
const { bounds } = this
|
||||||
|
const newValue = value || bounds
|
||||||
|
const minAmaxProps = {
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
}
|
||||||
|
const nextBounds = newValue.map((v, i) => this.trimAlignValue(v, i, minAmaxProps))
|
||||||
|
if (nextBounds.length === bounds.length && nextBounds.every((v, i) => v === bounds[i])) return
|
||||||
|
|
||||||
const { bounds } = this.state;
|
this.setState({ bounds: nextBounds })
|
||||||
const value = nextProps.value || bounds;
|
|
||||||
const nextBounds = value.map((v, i) => this.trimAlignValue(v, i, nextProps));
|
|
||||||
if (nextBounds.length === bounds.length && nextBounds.every((v, i) => v === bounds[i])) return;
|
|
||||||
|
|
||||||
this.setState({ bounds: nextBounds });
|
if (bounds.some(v => utils.isValueOutOfRange(v, minAmaxProps))) {
|
||||||
|
const newValues = newValue.map((v) => {
|
||||||
|
return utils.ensureValueInRange(v, minAmaxProps)
|
||||||
|
})
|
||||||
|
this.$emit('change', newValues)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChange (state) {
|
||||||
|
const isNotControlled = !hasProp(this, 'value')
|
||||||
|
if (isNotControlled) {
|
||||||
|
this.setState(state)
|
||||||
|
} else if (state.handle !== undefined) {
|
||||||
|
this.setState({ handle: state.handle })
|
||||||
|
}
|
||||||
|
|
||||||
if (bounds.some(v => utils.isValueOutOfRange(v, nextProps))) {
|
const data = { ...this.$data, ...state }
|
||||||
const newValues = value.map((v) => {
|
const changedValue = data.bounds
|
||||||
return utils.ensureValueInRange(v, nextProps);
|
this.$emit('change', changedValue)
|
||||||
});
|
},
|
||||||
this.props.onChange(newValues);
|
onStart (position) {
|
||||||
}
|
const { bounds } = this
|
||||||
}
|
this.$emit('beforeChange', bounds)
|
||||||
|
|
||||||
onChange(state) {
|
const value = this.calcValueByPos(position)
|
||||||
const props = this.props;
|
|
||||||
const isNotControlled = !('value' in props);
|
|
||||||
if (isNotControlled) {
|
|
||||||
this.setState(state);
|
|
||||||
} else if (state.handle !== undefined) {
|
|
||||||
this.setState({ handle: state.handle });
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = { ...this.state, ...state };
|
const closestBound = this.getClosestBound(value)
|
||||||
const changedValue = data.bounds;
|
this.prevMovedHandleIndex = this.getBoundNeedMoving(value, closestBound)
|
||||||
props.onChange(changedValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
onStart(position) {
|
this.setState({
|
||||||
const props = this.props;
|
handle: this.prevMovedHandleIndex,
|
||||||
const state = this.state;
|
recent: this.prevMovedHandleIndex,
|
||||||
const bounds = this.getValue();
|
})
|
||||||
props.onBeforeChange(bounds);
|
|
||||||
|
|
||||||
const value = this.calcValueByPos(position);
|
const prevValue = bounds[this.prevMovedHandleIndex]
|
||||||
this.startValue = value;
|
if (value === prevValue) return
|
||||||
this.startPosition = position;
|
|
||||||
|
|
||||||
const closestBound = this.getClosestBound(value);
|
const nextBounds = [...bounds]
|
||||||
this.prevMovedHandleIndex = this.getBoundNeedMoving(value, closestBound);
|
nextBounds[this.prevMovedHandleIndex] = value
|
||||||
|
this.$emit('change', { bounds: nextBounds })
|
||||||
|
},
|
||||||
|
onEnd () {
|
||||||
|
this.removeDocumentEvents()
|
||||||
|
this.$emit('afterChange', this.bounds)
|
||||||
|
},
|
||||||
|
onMove (e, position) {
|
||||||
|
utils.pauseEvent(e)
|
||||||
|
const { bounds, handle } = this
|
||||||
|
const value = this.calcValueByPos(position)
|
||||||
|
const oldValue = bounds[handle]
|
||||||
|
if (value === oldValue) return
|
||||||
|
|
||||||
this.setState({
|
this.moveTo(value)
|
||||||
handle: this.prevMovedHandleIndex,
|
},
|
||||||
recent: this.prevMovedHandleIndex,
|
onKeyboard (e) {
|
||||||
});
|
const valueMutator = utils.getKeyboardValueMutator(e)
|
||||||
|
|
||||||
const prevValue = bounds[this.prevMovedHandleIndex];
|
if (valueMutator) {
|
||||||
if (value === prevValue) return;
|
utils.pauseEvent(e)
|
||||||
|
const { bounds, handle } = this
|
||||||
|
const oldValue = bounds[handle]
|
||||||
|
const mutatedValue = valueMutator(oldValue, this.$props)
|
||||||
|
const value = this.trimAlignValue(mutatedValue)
|
||||||
|
if (value === oldValue) return
|
||||||
|
const isFromKeyboardEvent = true
|
||||||
|
this.moveTo(value, isFromKeyboardEvent)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getClosestBound (value) {
|
||||||
|
const { bounds } = this
|
||||||
|
let closestBound = 0
|
||||||
|
for (let i = 1; i < bounds.length - 1; ++i) {
|
||||||
|
if (value > bounds[i]) { closestBound = i }
|
||||||
|
}
|
||||||
|
if (Math.abs(bounds[closestBound + 1] - value) < Math.abs(bounds[closestBound] - value)) {
|
||||||
|
closestBound = closestBound + 1
|
||||||
|
}
|
||||||
|
return closestBound
|
||||||
|
},
|
||||||
|
getBoundNeedMoving (value, closestBound) {
|
||||||
|
const { bounds, recent } = this
|
||||||
|
let boundNeedMoving = closestBound
|
||||||
|
const isAtTheSamePoint = (bounds[closestBound + 1] === bounds[closestBound])
|
||||||
|
|
||||||
const nextBounds = [...state.bounds];
|
if (isAtTheSamePoint && bounds[recent] === bounds[closestBound]) {
|
||||||
nextBounds[this.prevMovedHandleIndex] = value;
|
boundNeedMoving = recent
|
||||||
this.onChange({ bounds: nextBounds });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
onEnd = () => {
|
if (isAtTheSamePoint && (value !== bounds[closestBound + 1])) {
|
||||||
this.removeDocumentEvents();
|
boundNeedMoving = value < bounds[closestBound + 1] ? closestBound : closestBound + 1
|
||||||
this.props.onAfterChange(this.getValue());
|
}
|
||||||
}
|
return boundNeedMoving
|
||||||
|
},
|
||||||
|
getLowerBound () {
|
||||||
|
return this.bounds[0]
|
||||||
|
},
|
||||||
|
getUpperBound () {
|
||||||
|
const { bounds } = this
|
||||||
|
return bounds[bounds.length - 1]
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Returns an array of possible slider points, taking into account both
|
||||||
|
* `marks` and `step`. The result is cached.
|
||||||
|
*/
|
||||||
|
getPoints () {
|
||||||
|
const { marks, step, min, max } = this
|
||||||
|
const cache = this._getPointsCache
|
||||||
|
if (!cache || cache.marks !== marks || cache.step !== step) {
|
||||||
|
const pointsObject = { ...marks }
|
||||||
|
if (step !== null) {
|
||||||
|
for (let point = min; point <= max; point += step) {
|
||||||
|
pointsObject[point] = point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const points = Object.keys(pointsObject).map(parseFloat)
|
||||||
|
points.sort((a, b) => a - b)
|
||||||
|
this._getPointsCache = { marks, step, points }
|
||||||
|
}
|
||||||
|
return this._getPointsCache.points
|
||||||
|
},
|
||||||
|
moveTo (value, isFromKeyboardEvent) {
|
||||||
|
const { bounds, handle } = this
|
||||||
|
const nextBounds = [...bounds]
|
||||||
|
nextBounds[handle] = value
|
||||||
|
let nextHandle = handle
|
||||||
|
if (this.pushable !== false) {
|
||||||
|
this.pushSurroundingHandles(nextBounds, nextHandle)
|
||||||
|
} else if (this.allowCross) {
|
||||||
|
nextBounds.sort((a, b) => a - b)
|
||||||
|
nextHandle = nextBounds.indexOf(value)
|
||||||
|
}
|
||||||
|
this.$emit('change', {
|
||||||
|
handle: 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.setState({}, () => {
|
||||||
|
this.handlesRefs[nextHandle].focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pushSurroundingHandles (bounds, handle) {
|
||||||
|
const value = bounds[handle]
|
||||||
|
let { pushable: threshold } = this
|
||||||
|
threshold = Number(threshold)
|
||||||
|
|
||||||
onMove(e, position) {
|
let direction = 0
|
||||||
utils.pauseEvent(e);
|
if (bounds[handle + 1] - value < threshold) {
|
||||||
const state = this.state;
|
direction = +1 // push to right
|
||||||
|
}
|
||||||
|
if (value - bounds[handle - 1] < threshold) {
|
||||||
|
direction = -1 // push to left
|
||||||
|
}
|
||||||
|
|
||||||
const value = this.calcValueByPos(position);
|
if (direction === 0) { return }
|
||||||
const oldValue = state.bounds[state.handle];
|
|
||||||
if (value === oldValue) return;
|
|
||||||
|
|
||||||
this.moveTo(value);
|
const nextHandle = handle + direction
|
||||||
}
|
const diffToNext = direction * (bounds[nextHandle] - value)
|
||||||
|
if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
|
||||||
onKeyboard(e) {
|
// revert to original value if pushing is impossible
|
||||||
const valueMutator = utils.getKeyboardValueMutator(e);
|
bounds[handle] = bounds[nextHandle] - (direction * threshold)
|
||||||
|
}
|
||||||
if (valueMutator) {
|
},
|
||||||
utils.pauseEvent(e);
|
pushHandle (bounds, handle, direction, amount) {
|
||||||
const { state, props } = this;
|
const originalValue = bounds[handle]
|
||||||
const { bounds, handle } = state;
|
let currentValue = bounds[handle]
|
||||||
const oldValue = bounds[handle];
|
while (direction * (currentValue - originalValue) < amount) {
|
||||||
const mutatedValue = valueMutator(oldValue, props);
|
if (!this.pushHandleOnePoint(bounds, handle, direction)) {
|
||||||
const value = this.trimAlignValue(mutatedValue);
|
// can't push handle enough to create the needed `amount` gap, so we
|
||||||
if (value === oldValue) return;
|
// revert its position to the original value
|
||||||
const isFromKeyboardEvent = true;
|
bounds[handle] = originalValue
|
||||||
this.moveTo(value, isFromKeyboardEvent);
|
return false
|
||||||
}
|
}
|
||||||
}
|
currentValue = bounds[handle]
|
||||||
|
}
|
||||||
getValue() {
|
// the handle was pushed enough to create the needed `amount` gap
|
||||||
return this.state.bounds;
|
return true
|
||||||
}
|
},
|
||||||
|
pushHandleOnePoint (bounds, handle, direction) {
|
||||||
getClosestBound(value) {
|
const points = this.getPoints()
|
||||||
const { bounds } = this.state;
|
const pointIndex = points.indexOf(bounds[handle])
|
||||||
let closestBound = 0;
|
const nextPointIndex = pointIndex + direction
|
||||||
for (let i = 1; i < bounds.length - 1; ++i) {
|
if (nextPointIndex >= points.length || nextPointIndex < 0) {
|
||||||
if (value > bounds[i]) { closestBound = i; }
|
// reached the minimum or maximum available point, can't push anymore
|
||||||
}
|
return false
|
||||||
if (Math.abs(bounds[closestBound + 1] - value) < Math.abs(bounds[closestBound] - value)) {
|
}
|
||||||
closestBound = closestBound + 1;
|
const nextHandle = handle + direction
|
||||||
}
|
const nextValue = points[nextPointIndex]
|
||||||
return closestBound;
|
const { pushable: threshold } = this
|
||||||
}
|
const diffToNext = direction * (bounds[nextHandle] - nextValue)
|
||||||
|
if (!this.pushHandle(bounds, nextHandle, direction, threshold - diffToNext)) {
|
||||||
getBoundNeedMoving(value, closestBound) {
|
// couldn't push next handle, so we won't push this one either
|
||||||
const { bounds, recent } = this.state;
|
return false
|
||||||
let boundNeedMoving = closestBound;
|
}
|
||||||
const isAtTheSamePoint = (bounds[closestBound + 1] === bounds[closestBound]);
|
// push the handle
|
||||||
|
bounds[handle] = nextValue
|
||||||
if (isAtTheSamePoint && bounds[recent] === bounds[closestBound]) {
|
return true
|
||||||
boundNeedMoving = recent;
|
},
|
||||||
}
|
trimAlignValue (v, handle, nextProps = {}) {
|
||||||
|
const mergedProps = { ...this, ...nextProps }
|
||||||
if (isAtTheSamePoint && (value !== bounds[closestBound + 1])) {
|
const valInRange = utils.ensureValueInRange(v, mergedProps)
|
||||||
boundNeedMoving = value < bounds[closestBound + 1] ? closestBound : closestBound + 1;
|
const valNotConflict = this.ensureValueNotConflict(handle, valInRange, mergedProps)
|
||||||
}
|
return utils.ensureValuePrecision(valNotConflict, mergedProps)
|
||||||
return boundNeedMoving;
|
},
|
||||||
}
|
ensureValueNotConflict (handle, val, { allowCross, pushable: thershold }) {
|
||||||
|
const state = this.$data || {}
|
||||||
getLowerBound() {
|
const { bounds } = state
|
||||||
return this.state.bounds[0];
|
handle = handle === undefined ? state.handle : handle
|
||||||
}
|
thershold = Number(thershold)
|
||||||
|
/* eslint-disable eqeqeq */
|
||||||
getUpperBound() {
|
if (!allowCross && handle != null && bounds !== undefined) {
|
||||||
const { bounds } = this.state;
|
if (handle > 0 && val <= (bounds[handle - 1] + thershold)) {
|
||||||
return bounds[bounds.length - 1];
|
return bounds[handle - 1] + thershold
|
||||||
}
|
}
|
||||||
|
if (handle < bounds.length - 1 && val >= (bounds[handle + 1] - thershold)) {
|
||||||
/**
|
return bounds[handle + 1] - thershold
|
||||||
* Returns an array of possible slider points, taking into account both
|
|
||||||
* `marks` and `step`. The result is cached.
|
|
||||||
*/
|
|
||||||
getPoints() {
|
|
||||||
const { marks, step, min, max } = this.props;
|
|
||||||
const cache = this._getPointsCache;
|
|
||||||
if (!cache || cache.marks !== marks || cache.step !== step) {
|
|
||||||
const pointsObject = { ...marks };
|
|
||||||
if (step !== null) {
|
|
||||||
for (let point = min; point <= max; point += step) {
|
|
||||||
pointsObject[point] = point;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const points = Object.keys(pointsObject).map(parseFloat);
|
/* eslint-enable eqeqeq */
|
||||||
points.sort((a, b) => a - b);
|
return val
|
||||||
this._getPointsCache = { marks, step, points };
|
},
|
||||||
}
|
},
|
||||||
return this._getPointsCache.points;
|
render () {
|
||||||
}
|
|
||||||
|
|
||||||
moveTo(value, isFromKeyboardEvent) {
|
|
||||||
const { state, props } = this;
|
|
||||||
const nextBounds = [...state.bounds];
|
|
||||||
nextBounds[state.handle] = value;
|
|
||||||
let nextHandle = state.handle;
|
|
||||||
if (props.pushable !== false) {
|
|
||||||
this.pushSurroundingHandles(nextBounds, nextHandle);
|
|
||||||
} else if (props.allowCross) {
|
|
||||||
nextBounds.sort((a, b) => a - b);
|
|
||||||
nextHandle = nextBounds.indexOf(value);
|
|
||||||
}
|
|
||||||
this.onChange({
|
|
||||||
handle: 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.setState({}, () => {
|
|
||||||
this.handlesRefs[nextHandle].focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pushSurroundingHandles(bounds, handle) {
|
|
||||||
const value = bounds[handle];
|
|
||||||
let { pushable: threshold } = this.props;
|
|
||||||
threshold = Number(threshold);
|
|
||||||
|
|
||||||
let 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; }
|
|
||||||
|
|
||||||
const nextHandle = handle + direction;
|
|
||||||
const 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(bounds, handle, direction, amount) {
|
|
||||||
const originalValue = bounds[handle];
|
|
||||||
let 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(bounds, handle, direction) {
|
|
||||||
const points = this.getPoints();
|
|
||||||
const pointIndex = points.indexOf(bounds[handle]);
|
|
||||||
const nextPointIndex = pointIndex + direction;
|
|
||||||
if (nextPointIndex >= points.length || nextPointIndex < 0) {
|
|
||||||
// reached the minimum or maximum available point, can't push anymore
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const nextHandle = handle + direction;
|
|
||||||
const nextValue = points[nextPointIndex];
|
|
||||||
const { pushable: threshold } = this.props;
|
|
||||||
const 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(v, handle, nextProps = {}) {
|
|
||||||
const mergedProps = { ...this.props, ...nextProps };
|
|
||||||
const valInRange = utils.ensureValueInRange(v, mergedProps);
|
|
||||||
const valNotConflict = this.ensureValueNotConflict(handle, valInRange, mergedProps);
|
|
||||||
return utils.ensureValuePrecision(valNotConflict, mergedProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureValueNotConflict(handle, val, { allowCross, pushable: thershold }) {
|
|
||||||
const state = this.state || {};
|
|
||||||
const { bounds } = state;
|
|
||||||
handle = handle === undefined ? state.handle : 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
const {
|
||||||
handle,
|
handle,
|
||||||
bounds,
|
bounds,
|
||||||
} = this.state;
|
|
||||||
const {
|
|
||||||
prefixCls,
|
prefixCls,
|
||||||
vertical,
|
vertical,
|
||||||
included,
|
included,
|
||||||
|
@ -332,11 +313,11 @@ class Range extends React.Component {
|
||||||
trackStyle,
|
trackStyle,
|
||||||
handleStyle,
|
handleStyle,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
} = this.props;
|
} = this
|
||||||
|
|
||||||
const offsets = bounds.map(v => this.calcOffset(v));
|
const offsets = bounds.map(v => this.calcOffset(v))
|
||||||
|
|
||||||
const handleClassName = `${prefixCls}-handle`;
|
const handleClassName = `${prefixCls}-handle`
|
||||||
const handles = bounds.map((v, i) => handleGenerator({
|
const handles = bounds.map((v, i) => handleGenerator({
|
||||||
className: classNames({
|
className: classNames({
|
||||||
[handleClassName]: true,
|
[handleClassName]: true,
|
||||||
|
@ -354,14 +335,14 @@ class Range extends React.Component {
|
||||||
disabled,
|
disabled,
|
||||||
style: handleStyle[i],
|
style: handleStyle[i],
|
||||||
ref: h => this.saveHandle(i, h),
|
ref: h => this.saveHandle(i, h),
|
||||||
}));
|
}))
|
||||||
|
|
||||||
const tracks = bounds.slice(0, -1).map((_, index) => {
|
const tracks = bounds.slice(0, -1).map((_, index) => {
|
||||||
const i = index + 1;
|
const i = index + 1
|
||||||
const trackClassName = classNames({
|
const trackClassName = classNames({
|
||||||
[`${prefixCls}-track`]: true,
|
[`${prefixCls}-track`]: true,
|
||||||
[`${prefixCls}-track-${i}`]: true,
|
[`${prefixCls}-track-${i}`]: true,
|
||||||
});
|
})
|
||||||
return (
|
return (
|
||||||
<Track
|
<Track
|
||||||
className={trackClassName}
|
className={trackClassName}
|
||||||
|
@ -372,11 +353,11 @@ class Range extends React.Component {
|
||||||
style={trackStyle[index]}
|
style={trackStyle[index]}
|
||||||
key={i}
|
key={i}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
return { tracks, handles };
|
return { tracks, handles }
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createSlider(Range);
|
export default createSlider(Range)
|
||||||
|
|
|
@ -1,142 +1,142 @@
|
||||||
/* eslint-disable react/prop-types */
|
import PropTypes from '../../../_util/vue-types'
|
||||||
import React from 'react'
|
import warning from '../../../_util/warning'
|
||||||
import PropTypes from 'prop-types'
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
import warning from 'warning'
|
import { hasProp } from '../../../_util/props-util'
|
||||||
import Track from './common/Track'
|
import Track from './common/Track'
|
||||||
import createSlider from './common/createSlider'
|
import createSlider from './common/createSlider'
|
||||||
import * as utils from './utils'
|
import * as utils from './utils'
|
||||||
|
|
||||||
class Slider extends React.Component {
|
const Slider = {
|
||||||
static propTypes = {
|
mixins: [BaseMixin],
|
||||||
|
props: {
|
||||||
defaultValue: PropTypes.number,
|
defaultValue: PropTypes.number,
|
||||||
value: PropTypes.number,
|
value: PropTypes.number,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
autoFocus: PropTypes.bool,
|
autoFocus: PropTypes.bool,
|
||||||
tabIndex: PropTypes.number,
|
tabIndex: PropTypes.number,
|
||||||
};
|
},
|
||||||
|
data () {
|
||||||
|
const defaultValue = this.defaultValue !== undefined
|
||||||
|
? this.defaultValue : this.min
|
||||||
|
const value = this.value !== undefined
|
||||||
|
? this.value : defaultValue
|
||||||
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
const defaultValue = props.defaultValue !== undefined
|
|
||||||
? props.defaultValue : props.min
|
|
||||||
const value = props.value !== undefined
|
|
||||||
? props.value : defaultValue
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
value: this.trimAlignValue(value),
|
|
||||||
dragging: false,
|
|
||||||
}
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
warning(
|
warning(
|
||||||
!('minimumTrackStyle' in props),
|
!hasProp(this, 'minimumTrackStyle'),
|
||||||
'minimumTrackStyle will be deprecate, please use trackStyle instead.'
|
'minimumTrackStyle will be deprecate, please use trackStyle instead.'
|
||||||
)
|
)
|
||||||
warning(
|
warning(
|
||||||
!('maximumTrackStyle' in props),
|
!hasProp(this, 'maximumTrackStyle'),
|
||||||
'maximumTrackStyle will be deprecate, please use railStyle instead.'
|
'maximumTrackStyle will be deprecate, please use railStyle instead.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
return {
|
||||||
|
sValue: this.trimAlignValue(value),
|
||||||
componentDidMount () {
|
dragging: false,
|
||||||
const { autoFocus, disabled } = this.props
|
|
||||||
if (autoFocus && !disabled) {
|
|
||||||
this.focus()
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const { autoFocus, disabled } = this
|
||||||
|
if (autoFocus && !disabled) {
|
||||||
|
this.focus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler (val) {
|
||||||
|
const { min, max } = this
|
||||||
|
this.setChangeValue(val, min, max)
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
min (val) {
|
||||||
|
const { sValue, max } = this
|
||||||
|
this.setChangeValue(sValue, val, max)
|
||||||
|
},
|
||||||
|
max (val) {
|
||||||
|
const { sValue, min } = this
|
||||||
|
this.setChangeValue(sValue, min, val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setChangeValue (value, min, max) {
|
||||||
|
const minAmaxProps = {
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
}
|
||||||
|
const newValue = value !== undefined
|
||||||
|
? value : this.sValue
|
||||||
|
const nextValue = this.trimAlignValue(newValue, minAmaxProps)
|
||||||
|
if (nextValue === this.sValue) return
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
this.setState({ sValue: nextValue })
|
||||||
if (!('value' in nextProps || 'min' in nextProps || 'max' in nextProps)) return
|
if (utils.isValueOutOfRange(newValue, minAmaxProps)) {
|
||||||
|
this.$emit('change', nextValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChange (state) {
|
||||||
|
const isNotControlled = !hasProp(this, 'value')
|
||||||
|
if (isNotControlled) {
|
||||||
|
this.setState(state)
|
||||||
|
}
|
||||||
|
|
||||||
const prevValue = this.state.value
|
const changedValue = state.sValue
|
||||||
const value = nextProps.value !== undefined
|
this.$emit('change', changedValue)
|
||||||
? nextProps.value : prevValue
|
},
|
||||||
const nextValue = this.trimAlignValue(value, nextProps)
|
onStart (position) {
|
||||||
if (nextValue === prevValue) return
|
this.setState({ dragging: true })
|
||||||
|
const { sValue } = this
|
||||||
|
this.$emit('beforeChange', sValue)
|
||||||
|
|
||||||
this.setState({ value: nextValue })
|
const value = this.calcValueByPos(position)
|
||||||
if (utils.isValueOutOfRange(value, nextProps)) {
|
|
||||||
this.props.onChange(nextValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange (state) {
|
if (value === sValue) return
|
||||||
const props = this.props
|
|
||||||
const isNotControlled = !('value' in props)
|
|
||||||
if (isNotControlled) {
|
|
||||||
this.setState(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
const changedValue = state.value
|
this.prevMovedHandleIndex = 0
|
||||||
props.onChange(changedValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
onStart (position) {
|
this.onChange({ sValue: value })
|
||||||
this.setState({ dragging: true })
|
},
|
||||||
const props = this.props
|
onEnd () {
|
||||||
const prevValue = this.getValue()
|
this.setState({ dragging: false })
|
||||||
props.onBeforeChange(prevValue)
|
this.removeDocumentEvents()
|
||||||
|
this.$emit('afterChange', this.sValue)
|
||||||
const value = this.calcValueByPos(position)
|
},
|
||||||
this.startValue = value
|
onMove (e, position) {
|
||||||
this.startPosition = position
|
|
||||||
|
|
||||||
if (value === prevValue) return
|
|
||||||
|
|
||||||
this.prevMovedHandleIndex = 0
|
|
||||||
|
|
||||||
this.onChange({ value })
|
|
||||||
}
|
|
||||||
|
|
||||||
onEnd = () => {
|
|
||||||
this.setState({ dragging: false })
|
|
||||||
this.removeDocumentEvents()
|
|
||||||
this.props.onAfterChange(this.getValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
onMove (e, position) {
|
|
||||||
utils.pauseEvent(e)
|
|
||||||
const { value: oldValue } = this.state
|
|
||||||
const value = this.calcValueByPos(position)
|
|
||||||
if (value === oldValue) return
|
|
||||||
|
|
||||||
this.onChange({ value })
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyboard (e) {
|
|
||||||
const valueMutator = utils.getKeyboardValueMutator(e)
|
|
||||||
|
|
||||||
if (valueMutator) {
|
|
||||||
utils.pauseEvent(e)
|
utils.pauseEvent(e)
|
||||||
const state = this.state
|
const { sValue } = this
|
||||||
const oldValue = state.value
|
const value = this.calcValueByPos(position)
|
||||||
const mutatedValue = valueMutator(oldValue, this.props)
|
if (value === sValue) return
|
||||||
const value = this.trimAlignValue(mutatedValue)
|
|
||||||
if (value === oldValue) return
|
|
||||||
|
|
||||||
this.onChange({ value })
|
this.onChange({ sValue: value })
|
||||||
}
|
},
|
||||||
}
|
onKeyboard (e) {
|
||||||
|
const valueMutator = utils.getKeyboardValueMutator(e)
|
||||||
|
|
||||||
getValue () {
|
if (valueMutator) {
|
||||||
return this.state.value
|
utils.pauseEvent(e)
|
||||||
}
|
const { sValue } = this
|
||||||
|
const mutatedValue = valueMutator(sValue, this.$props)
|
||||||
getLowerBound () {
|
const value = this.trimAlignValue(mutatedValue)
|
||||||
return this.props.min
|
if (value === sValue) return
|
||||||
}
|
|
||||||
|
|
||||||
getUpperBound () {
|
|
||||||
return this.state.value
|
|
||||||
}
|
|
||||||
|
|
||||||
trimAlignValue (v, nextProps = {}) {
|
|
||||||
const mergedProps = { ...this.props, ...nextProps }
|
|
||||||
const val = utils.ensureValueInRange(v, mergedProps)
|
|
||||||
return utils.ensureValuePrecision(val, mergedProps)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.onChange({ sValue: value })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLowerBound () {
|
||||||
|
return this.min
|
||||||
|
},
|
||||||
|
getUpperBound () {
|
||||||
|
return this.sValue
|
||||||
|
},
|
||||||
|
trimAlignValue (v, nextProps = {}) {
|
||||||
|
const mergedProps = { ...this.$props, ...nextProps }
|
||||||
|
const val = utils.ensureValueInRange(v, mergedProps)
|
||||||
|
return utils.ensureValuePrecision(val, mergedProps)
|
||||||
|
},
|
||||||
|
},
|
||||||
render () {
|
render () {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
@ -150,7 +150,7 @@ class Slider extends React.Component {
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
handle: handleGenerator,
|
handle: handleGenerator,
|
||||||
} = this.props
|
} = this
|
||||||
const { value, dragging } = this.state
|
const { value, dragging } = this.state
|
||||||
const offset = this.calcOffset(value)
|
const offset = this.calcOffset(value)
|
||||||
const handle = handleGenerator({
|
const handle = handleGenerator({
|
||||||
|
@ -183,9 +183,8 @@ class Slider extends React.Component {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
return { tracks: track, handles: handle }
|
return { tracks: track, handles: handle }
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createSlider(Slider)
|
export default createSlider(Slider)
|
||||||
|
|
|
@ -1,66 +1,71 @@
|
||||||
import React from 'react'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
const Marks = ({
|
const Marks = {
|
||||||
className,
|
functional: true,
|
||||||
vertical,
|
render (createElement, context) {
|
||||||
marks,
|
const {
|
||||||
included,
|
className,
|
||||||
upperBound,
|
vertical,
|
||||||
lowerBound,
|
marks,
|
||||||
max, min,
|
included,
|
||||||
onClickLabel,
|
upperBound,
|
||||||
}) => {
|
lowerBound,
|
||||||
const marksKeys = Object.keys(marks)
|
max, min,
|
||||||
const marksCount = marksKeys.length
|
} = context.props
|
||||||
const unit = marksCount > 1 ? 100 / (marksCount - 1) : 100
|
const { clickLabel } = context.listeners
|
||||||
const markWidth = unit * 0.9
|
const marksKeys = Object.keys(marks)
|
||||||
|
const marksCount = marksKeys.length
|
||||||
|
const unit = marksCount > 1 ? 100 / (marksCount - 1) : 100
|
||||||
|
const markWidth = unit * 0.9
|
||||||
|
|
||||||
const range = max - min
|
const range = max - min
|
||||||
const elements = marksKeys.map(parseFloat).sort((a, b) => a - b).map(point => {
|
const elements = marksKeys.map(parseFloat).sort((a, b) => a - b).map(point => {
|
||||||
const markPoint = marks[point]
|
const markPoint = marks[point]
|
||||||
const markPointIsObject = typeof markPoint === 'object' &&
|
// todo
|
||||||
!React.isValidElement(markPoint)
|
// const markPointIsObject = typeof markPoint === 'object' &&
|
||||||
const markLabel = markPointIsObject ? markPoint.label : markPoint
|
// !React.isValidElement(markPoint)
|
||||||
if (!markLabel && markLabel !== 0) {
|
const markPointIsObject = typeof markPoint === 'object'
|
||||||
return null
|
const markLabel = markPointIsObject ? markPoint.label : markPoint
|
||||||
}
|
if (!markLabel && markLabel !== 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const isActive = (!included && point === upperBound) ||
|
const isActive = (!included && point === upperBound) ||
|
||||||
(included && point <= upperBound && point >= lowerBound)
|
(included && point <= upperBound && point >= lowerBound)
|
||||||
const markClassName = classNames({
|
const markClassName = classNames({
|
||||||
[`${className}-text`]: true,
|
[`${className}-text`]: true,
|
||||||
[`${className}-text-active`]: isActive,
|
[`${className}-text-active`]: isActive,
|
||||||
|
})
|
||||||
|
|
||||||
|
const bottomStyle = {
|
||||||
|
marginBottom: '-50%',
|
||||||
|
bottom: `${(point - min) / range * 100}%`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftStyle = {
|
||||||
|
width: `${markWidth}%`,
|
||||||
|
marginLeft: `${-markWidth / 2}%`,
|
||||||
|
left: `${(point - min) / range * 100}%`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = vertical ? bottomStyle : leftStyle
|
||||||
|
const markStyle = markPointIsObject
|
||||||
|
? { ...style, ...markPoint.style } : style
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
class={markClassName}
|
||||||
|
style={markStyle}
|
||||||
|
key={point}
|
||||||
|
onMouseDown={(e) => clickLabel(e, point)}
|
||||||
|
onTouchStart={(e) => clickLabel(e, point)}
|
||||||
|
>
|
||||||
|
{markLabel}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const bottomStyle = {
|
return <div class={className}>{elements}</div>
|
||||||
marginBottom: '-50%',
|
},
|
||||||
bottom: `${(point - min) / range * 100}%`,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const leftStyle = {
|
|
||||||
width: `${markWidth}%`,
|
|
||||||
marginLeft: `${-markWidth / 2}%`,
|
|
||||||
left: `${(point - min) / range * 100}%`,
|
|
||||||
}
|
|
||||||
|
|
||||||
const style = vertical ? bottomStyle : leftStyle
|
|
||||||
const markStyle = markPointIsObject
|
|
||||||
? { ...style, ...markPoint.style } : style
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className={markClassName}
|
|
||||||
style={markStyle}
|
|
||||||
key={point}
|
|
||||||
onMouseDown={(e) => onClickLabel(e, point)}
|
|
||||||
onTouchStart={(e) => onClickLabel(e, point)}
|
|
||||||
>
|
|
||||||
{markLabel}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return <div className={className}>{elements}</div>
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Marks
|
export default Marks
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import warning from 'warning'
|
import warning from '../../../_util/warning'
|
||||||
|
|
||||||
const calcPoints = (vertical, marks, dots, step, min, max) => {
|
const calcPoints = (vertical, marks, dots, step, min, max) => {
|
||||||
warning(
|
warning(
|
||||||
|
@ -17,28 +16,32 @@ const calcPoints = (vertical, marks, dots, step, min, max) => {
|
||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
const Steps = ({ prefixCls, vertical, marks, dots, step, included,
|
const Steps = {
|
||||||
lowerBound, upperBound, max, min, dotStyle, activeDotStyle }) => {
|
functional: true,
|
||||||
const range = max - min
|
render (createElement, context) {
|
||||||
const elements = calcPoints(vertical, marks, dots, step, min, max).map((point) => {
|
const { prefixCls, vertical, marks, dots, step, included,
|
||||||
const offset = `${Math.abs(point - min) / range * 100}%`
|
lowerBound, upperBound, max, min, dotStyle, activeDotStyle } = context.data
|
||||||
|
const range = max - min
|
||||||
|
const elements = calcPoints(vertical, marks, dots, step, min, max).map((point) => {
|
||||||
|
const offset = `${Math.abs(point - min) / range * 100}%`
|
||||||
|
|
||||||
const isActived = (!included && point === upperBound) ||
|
const isActived = (!included && point === upperBound) ||
|
||||||
(included && point <= upperBound && point >= lowerBound)
|
(included && point <= upperBound && point >= lowerBound)
|
||||||
let style = vertical ? { bottom: offset, ...dotStyle } : { left: offset, ...dotStyle }
|
let style = vertical ? { bottom: offset, ...dotStyle } : { left: offset, ...dotStyle }
|
||||||
if (isActived) {
|
if (isActived) {
|
||||||
style = { ...style, ...activeDotStyle }
|
style = { ...style, ...activeDotStyle }
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointClassName = classNames({
|
const pointClassName = classNames({
|
||||||
[`${prefixCls}-dot`]: true,
|
[`${prefixCls}-dot`]: true,
|
||||||
[`${prefixCls}-dot-active`]: isActived,
|
[`${prefixCls}-dot-active`]: isActived,
|
||||||
|
})
|
||||||
|
|
||||||
|
return <span className={pointClassName} style={style} key={point} />
|
||||||
})
|
})
|
||||||
|
|
||||||
return <span className={pointClassName} style={style} key={point} />
|
return <div className={`${prefixCls}-step`}>{elements}</div>
|
||||||
})
|
},
|
||||||
|
|
||||||
return <div className={`${prefixCls}-step`}>{elements}</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Steps
|
export default Steps
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import addEventListener from 'rc-util/lib/Dom/addEventListener'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import warning from 'warning'
|
import PropTypes from '../../../_util/vue-types'
|
||||||
|
import addEventListener from '../../../_util/Dom/addEventListener'
|
||||||
|
import warning from '../../../_util/warning'
|
||||||
|
import { initDefaultProps } from '../../../_util/props-util'
|
||||||
import Steps from './Steps'
|
import Steps from './Steps'
|
||||||
import Marks from './Marks'
|
import Marks from './Marks'
|
||||||
import Handle from '../Handle'
|
import Handle from '../Handle'
|
||||||
|
@ -11,42 +11,32 @@ import * as utils from '../utils'
|
||||||
function noop () {}
|
function noop () {}
|
||||||
|
|
||||||
export default function createSlider (Component) {
|
export default function createSlider (Component) {
|
||||||
return class ComponentEnhancer extends Component {
|
// const displayName = `ComponentEnhancer(${Component.displayName})`
|
||||||
static displayName = `ComponentEnhancer(${Component.displayName})`;
|
const propTypes = {
|
||||||
static propTypes = {
|
...Component.propTypes,
|
||||||
...Component.propTypes,
|
min: PropTypes.number,
|
||||||
min: PropTypes.number,
|
max: PropTypes.number,
|
||||||
max: PropTypes.number,
|
step: PropTypes.number,
|
||||||
step: PropTypes.number,
|
marks: PropTypes.object,
|
||||||
marks: PropTypes.object,
|
included: PropTypes.bool,
|
||||||
included: PropTypes.bool,
|
prefixCls: PropTypes.string,
|
||||||
className: PropTypes.string,
|
disabled: PropTypes.bool,
|
||||||
prefixCls: PropTypes.string,
|
handle: PropTypes.func,
|
||||||
disabled: PropTypes.bool,
|
dots: PropTypes.bool,
|
||||||
children: PropTypes.any,
|
vertical: PropTypes.bool,
|
||||||
onBeforeChange: PropTypes.func,
|
minimumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
|
||||||
onChange: PropTypes.func,
|
maximumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
|
||||||
onAfterChange: PropTypes.func,
|
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
||||||
handle: PropTypes.func,
|
trackStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
||||||
dots: PropTypes.bool,
|
railStyle: PropTypes.object,
|
||||||
vertical: PropTypes.bool,
|
dotStyle: PropTypes.object,
|
||||||
style: PropTypes.object,
|
activeDotStyle: PropTypes.object,
|
||||||
minimumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
|
autoFocus: PropTypes.bool,
|
||||||
maximumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
|
}
|
||||||
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
return {
|
||||||
trackStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
props: initDefaultProps(propTypes, {
|
||||||
railStyle: PropTypes.object,
|
|
||||||
dotStyle: PropTypes.object,
|
|
||||||
activeDotStyle: PropTypes.object,
|
|
||||||
autoFocus: PropTypes.bool,
|
|
||||||
onFocus: PropTypes.func,
|
|
||||||
onBlur: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
...Component.defaultProps,
|
...Component.defaultProps,
|
||||||
prefixCls: 'rc-slider',
|
prefixCls: 'rc-slider',
|
||||||
className: '',
|
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
step: 1,
|
step: 1,
|
||||||
|
@ -55,9 +45,6 @@ export default function createSlider (Component) {
|
||||||
delete restProps.dragging
|
delete restProps.dragging
|
||||||
return <Handle {...restProps} key={index} />
|
return <Handle {...restProps} key={index} />
|
||||||
},
|
},
|
||||||
onBeforeChange: noop,
|
|
||||||
onChange: noop,
|
|
||||||
onAfterChange: noop,
|
|
||||||
included: true,
|
included: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
dots: false,
|
dots: false,
|
||||||
|
@ -67,13 +54,10 @@ export default function createSlider (Component) {
|
||||||
railStyle: {},
|
railStyle: {},
|
||||||
dotStyle: {},
|
dotStyle: {},
|
||||||
activeDotStyle: {},
|
activeDotStyle: {},
|
||||||
};
|
}),
|
||||||
|
data () {
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
const { step, max, min } = props
|
const { step, max, min } = this
|
||||||
warning(
|
warning(
|
||||||
step && Math.floor(step) === step ? (max - min) % step === 0 : true,
|
step && Math.floor(step) === step ? (max - min) % step === 0 : true,
|
||||||
'Slider[max] - Slider[min] (%s) should be a multiple of Slider[step] (%s)',
|
'Slider[max] - Slider[min] (%s) should be a multiple of Slider[step] (%s)',
|
||||||
|
@ -82,190 +66,163 @@ export default function createSlider (Component) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
this.handlesRefs = {}
|
this.handlesRefs = {}
|
||||||
}
|
return {}
|
||||||
|
},
|
||||||
componentWillUnmount () {
|
beforeDestroy () {
|
||||||
if (super.componentWillUnmount) super.componentWillUnmount()
|
this.$nextTick(() => {
|
||||||
this.removeDocumentEvents()
|
// if (super.componentWillUnmount) super.componentWillUnmount()
|
||||||
}
|
this.removeDocumentEvents()
|
||||||
|
})
|
||||||
componentDidMount () {
|
},
|
||||||
// Snapshot testing cannot handle refs, so be sure to null-check this.
|
mounted () {
|
||||||
this.document = this.sliderRef && this.sliderRef.ownerDocument
|
this.$nextTick(() => {
|
||||||
}
|
// Snapshot testing cannot handle refs, so be sure to null-check this.
|
||||||
|
this.document = this.$refs.sliderRef && this.$refs.sliderRef.ownerDocument
|
||||||
onMouseDown = (e) => {
|
})
|
||||||
if (e.button !== 0) { return }
|
},
|
||||||
|
methods: {
|
||||||
const isVertical = this.props.vertical
|
onMouseDown (e) {
|
||||||
let position = utils.getMousePosition(isVertical, e)
|
if (e.button !== 0) { return }
|
||||||
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
|
const isVertical = this.vertical
|
||||||
this.dragOffset = 0
|
let position = utils.getMousePosition(isVertical, e)
|
||||||
} else {
|
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||||
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
|
this.dragOffset = 0
|
||||||
this.dragOffset = position - handlePosition
|
} else {
|
||||||
position = handlePosition
|
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
|
||||||
}
|
this.dragOffset = position - handlePosition
|
||||||
this.removeDocumentEvents()
|
position = handlePosition
|
||||||
this.onStart(position)
|
|
||||||
this.addDocumentMouseEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
onTouchStart = (e) => {
|
|
||||||
if (utils.isNotTouchEvent(e)) return
|
|
||||||
|
|
||||||
const isVertical = this.props.vertical
|
|
||||||
let position = utils.getTouchPosition(isVertical, e)
|
|
||||||
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
|
|
||||||
this.dragOffset = 0
|
|
||||||
} else {
|
|
||||||
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
|
|
||||||
this.dragOffset = position - handlePosition
|
|
||||||
position = handlePosition
|
|
||||||
}
|
|
||||||
this.onStart(position)
|
|
||||||
this.addDocumentTouchEvents()
|
|
||||||
utils.pauseEvent(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocus = (e) => {
|
|
||||||
const { onFocus, vertical } = this.props
|
|
||||||
if (utils.isEventFromHandle(e, this.handlesRefs)) {
|
|
||||||
const handlePosition = utils.getHandleCenterPosition(vertical, e.target)
|
|
||||||
this.dragOffset = 0
|
|
||||||
this.onStart(handlePosition)
|
|
||||||
utils.pauseEvent(e)
|
|
||||||
if (onFocus) {
|
|
||||||
onFocus(e)
|
|
||||||
}
|
}
|
||||||
}
|
this.removeDocumentEvents()
|
||||||
}
|
this.onStart(position)
|
||||||
|
this.addDocumentMouseEvents()
|
||||||
|
},
|
||||||
|
onTouchStart (e) {
|
||||||
|
if (utils.isNotTouchEvent(e)) return
|
||||||
|
|
||||||
onBlur = (e) => {
|
const isVertical = this.vertical
|
||||||
const { onBlur } = this.props
|
let position = utils.getTouchPosition(isVertical, e)
|
||||||
this.onEnd(e)
|
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||||
if (onBlur) {
|
this.dragOffset = 0
|
||||||
onBlur(e)
|
} else {
|
||||||
}
|
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
|
||||||
};
|
this.dragOffset = position - handlePosition
|
||||||
|
position = handlePosition
|
||||||
|
}
|
||||||
|
this.onStart(position)
|
||||||
|
this.addDocumentTouchEvents()
|
||||||
|
utils.pauseEvent(e)
|
||||||
|
},
|
||||||
|
onFocus (e) {
|
||||||
|
const { vertical } = this
|
||||||
|
if (utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||||
|
const handlePosition = utils.getHandleCenterPosition(vertical, e.target)
|
||||||
|
this.dragOffset = 0
|
||||||
|
this.onStart(handlePosition)
|
||||||
|
utils.pauseEvent(e)
|
||||||
|
this.$emit('focus', e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onBlur (e) {
|
||||||
|
this.onEnd(e)
|
||||||
|
this.$emit('blur', e)
|
||||||
|
},
|
||||||
|
addDocumentTouchEvents () {
|
||||||
|
// just work for Chrome iOS Safari and Android Browser
|
||||||
|
this.onTouchMoveListener = addEventListener(this.document, 'touchmove', this.onTouchMove)
|
||||||
|
this.onTouchUpListener = addEventListener(this.document, 'touchend', this.onEnd)
|
||||||
|
},
|
||||||
|
addDocumentMouseEvents () {
|
||||||
|
this.onMouseMoveListener = addEventListener(this.document, 'mousemove', this.onMouseMove)
|
||||||
|
this.onMouseUpListener = addEventListener(this.document, 'mouseup', this.onEnd)
|
||||||
|
},
|
||||||
|
removeDocumentEvents () {
|
||||||
|
/* eslint-disable no-unused-expressions */
|
||||||
|
this.onTouchMoveListener && this.onTouchMoveListener.remove()
|
||||||
|
this.onTouchUpListener && this.onTouchUpListener.remove()
|
||||||
|
|
||||||
addDocumentTouchEvents () {
|
this.onMouseMoveListener && this.onMouseMoveListener.remove()
|
||||||
// just work for Chrome iOS Safari and Android Browser
|
this.onMouseUpListener && this.onMouseUpListener.remove()
|
||||||
this.onTouchMoveListener = addEventListener(this.document, 'touchmove', this.onTouchMove)
|
/* eslint-enable no-unused-expressions */
|
||||||
this.onTouchUpListener = addEventListener(this.document, 'touchend', this.onEnd)
|
},
|
||||||
}
|
onMouseUp () {
|
||||||
|
if (this.handlesRefs[this.prevMovedHandleIndex]) {
|
||||||
|
this.handlesRefs[this.prevMovedHandleIndex].clickFocus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMouseMove (e) {
|
||||||
|
if (!this.$refs.sliderRef) {
|
||||||
|
this.onEnd()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const position = utils.getMousePosition(this.vertical, e)
|
||||||
|
this.onMove(e, position - this.dragOffset)
|
||||||
|
},
|
||||||
|
onTouchMove (e) {
|
||||||
|
if (utils.isNotTouchEvent(e) || !this.$refs.sliderRef) {
|
||||||
|
this.onEnd()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
addDocumentMouseEvents () {
|
const position = utils.getTouchPosition(this.vertical, e)
|
||||||
this.onMouseMoveListener = addEventListener(this.document, 'mousemove', this.onMouseMove)
|
this.onMove(e, position - this.dragOffset)
|
||||||
this.onMouseUpListener = addEventListener(this.document, 'mouseup', this.onEnd)
|
},
|
||||||
}
|
onKeyDown (e) {
|
||||||
|
if (this.$refs.sliderRef && utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||||
|
this.onKeyboard(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focus () {
|
||||||
|
if (!this.disabled) {
|
||||||
|
this.handlesRefs[0].focus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
blur () {
|
||||||
|
if (!this.disabled) {
|
||||||
|
this.handlesRefs[0].blur()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSliderStart () {
|
||||||
|
const slider = this.$refs.sliderRef
|
||||||
|
const rect = slider.getBoundingClientRect()
|
||||||
|
|
||||||
removeDocumentEvents () {
|
return this.vertical ? rect.top : rect.left
|
||||||
/* eslint-disable no-unused-expressions */
|
},
|
||||||
this.onTouchMoveListener && this.onTouchMoveListener.remove()
|
getSliderLength () {
|
||||||
this.onTouchUpListener && this.onTouchUpListener.remove()
|
const slider = this.$refs.sliderRef
|
||||||
|
if (!slider) {
|
||||||
this.onMouseMoveListener && this.onMouseMoveListener.remove()
|
return 0
|
||||||
this.onMouseUpListener && this.onMouseUpListener.remove()
|
}
|
||||||
/* eslint-enable no-unused-expressions */
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseUp = () => {
|
|
||||||
if (this.handlesRefs[this.prevMovedHandleIndex]) {
|
|
||||||
this.handlesRefs[this.prevMovedHandleIndex].clickFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMouseMove = (e) => {
|
|
||||||
if (!this.sliderRef) {
|
|
||||||
this.onEnd()
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const position = utils.getMousePosition(this.props.vertical, e)
|
|
||||||
this.onMove(e, position - this.dragOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
onTouchMove = (e) => {
|
|
||||||
if (utils.isNotTouchEvent(e) || !this.sliderRef) {
|
|
||||||
this.onEnd()
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const position = utils.getTouchPosition(this.props.vertical, e)
|
|
||||||
this.onMove(e, position - this.dragOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyDown = (e) => {
|
|
||||||
if (this.sliderRef && utils.isEventFromHandle(e, this.handlesRefs)) {
|
|
||||||
this.onKeyboard(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
focus () {
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.handlesRefs[0].focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blur () {
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.handlesRefs[0].blur()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSliderStart () {
|
|
||||||
const slider = this.sliderRef
|
|
||||||
const rect = slider.getBoundingClientRect()
|
|
||||||
|
|
||||||
return this.props.vertical ? rect.top : rect.left
|
|
||||||
}
|
|
||||||
|
|
||||||
getSliderLength () {
|
|
||||||
const slider = this.sliderRef
|
|
||||||
if (!slider) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const coords = slider.getBoundingClientRect()
|
|
||||||
return this.props.vertical ? coords.height : coords.width
|
|
||||||
}
|
|
||||||
|
|
||||||
calcValue (offset) {
|
|
||||||
const { vertical, min, max } = this.props
|
|
||||||
const ratio = Math.abs(Math.max(offset, 0) / this.getSliderLength())
|
|
||||||
const value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
calcValueByPos (position) {
|
|
||||||
const pixelOffset = position - this.getSliderStart()
|
|
||||||
const nextValue = this.trimAlignValue(this.calcValue(pixelOffset))
|
|
||||||
return nextValue
|
|
||||||
}
|
|
||||||
|
|
||||||
calcOffset (value) {
|
|
||||||
const { min, max } = this.props
|
|
||||||
const ratio = (value - min) / (max - min)
|
|
||||||
return ratio * 100
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSlider = (slider) => {
|
|
||||||
this.sliderRef = slider
|
|
||||||
}
|
|
||||||
|
|
||||||
saveHandle (index, handle) {
|
|
||||||
this.handlesRefs[index] = handle
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickMarkLabel = (e, value) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
this.onChange({ value })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const coords = slider.getBoundingClientRect()
|
||||||
|
return this.vertical ? coords.height : coords.width
|
||||||
|
},
|
||||||
|
calcValue (offset) {
|
||||||
|
const { vertical, min, max } = this
|
||||||
|
const ratio = Math.abs(Math.max(offset, 0) / this.getSliderLength())
|
||||||
|
const value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
calcValueByPos (position) {
|
||||||
|
const pixelOffset = position - this.getSliderStart()
|
||||||
|
const nextValue = this.trimAlignValue(this.calcValue(pixelOffset))
|
||||||
|
return nextValue
|
||||||
|
},
|
||||||
|
calcOffset (value) {
|
||||||
|
const { min, max } = this.props
|
||||||
|
const ratio = (value - min) / (max - min)
|
||||||
|
return ratio * 100
|
||||||
|
},
|
||||||
|
saveHandle (index, handle) {
|
||||||
|
this.handlesRefs[index] = handle
|
||||||
|
},
|
||||||
|
onClickMarkLabel (e, value) {
|
||||||
|
e.stopPropagation()
|
||||||
|
this.$emit('change', { value })
|
||||||
|
},
|
||||||
|
},
|
||||||
render () {
|
render () {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
className,
|
|
||||||
marks,
|
marks,
|
||||||
dots,
|
dots,
|
||||||
step,
|
step,
|
||||||
|
@ -274,35 +231,46 @@ export default function createSlider (Component) {
|
||||||
vertical,
|
vertical,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
children,
|
|
||||||
maximumTrackStyle,
|
maximumTrackStyle,
|
||||||
style,
|
|
||||||
railStyle,
|
railStyle,
|
||||||
dotStyle,
|
dotStyle,
|
||||||
activeDotStyle,
|
activeDotStyle,
|
||||||
} = this.props
|
} = this
|
||||||
const { tracks, handles } = super.render()
|
const { tracks, handles } = super.render()
|
||||||
|
|
||||||
const sliderClassName = classNames(prefixCls, {
|
const sliderClassName = classNames(prefixCls, {
|
||||||
[`${prefixCls}-with-marks`]: Object.keys(marks).length,
|
[`${prefixCls}-with-marks`]: Object.keys(marks).length,
|
||||||
[`${prefixCls}-disabled`]: disabled,
|
[`${prefixCls}-disabled`]: disabled,
|
||||||
[`${prefixCls}-vertical`]: vertical,
|
[`${prefixCls}-vertical`]: vertical,
|
||||||
[className]: className,
|
|
||||||
})
|
})
|
||||||
|
const markProps = {
|
||||||
|
props: {
|
||||||
|
vertical,
|
||||||
|
marks,
|
||||||
|
included,
|
||||||
|
lowerBound: this.getLowerBound(),
|
||||||
|
upperBound: this.getUpperBound(),
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
className: `${prefixCls}-mark`,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
clickLabel: disabled ? noop : this.onClickMarkLabel,
|
||||||
|
},
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={this.saveSlider}
|
ref='sliderRef'
|
||||||
className={sliderClassName}
|
class={sliderClassName}
|
||||||
onTouchStart={disabled ? noop : this.onTouchStart}
|
onTouchStart={disabled ? noop : this.onTouchStart}
|
||||||
onMouseDown={disabled ? noop : this.onMouseDown}
|
onMouseDown={disabled ? noop : this.onMouseDown}
|
||||||
onMouseUp={disabled ? noop : this.onMouseUp}
|
onMouseUp={disabled ? noop : this.onMouseUp}
|
||||||
onKeyDown={disabled ? noop : this.onKeyDown}
|
onKeyDown={disabled ? noop : this.onKeyDown}
|
||||||
onFocus={disabled ? noop : this.onFocus}
|
onFocus={disabled ? noop : this.onFocus}
|
||||||
onBlur={disabled ? noop : this.onBlur}
|
onBlur={disabled ? noop : this.onBlur}
|
||||||
style={style}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`${prefixCls}-rail`}
|
class={`${prefixCls}-rail`}
|
||||||
style={{
|
style={{
|
||||||
...maximumTrackStyle,
|
...maximumTrackStyle,
|
||||||
...railStyle,
|
...railStyle,
|
||||||
|
@ -325,19 +293,11 @@ export default function createSlider (Component) {
|
||||||
/>
|
/>
|
||||||
{handles}
|
{handles}
|
||||||
<Marks
|
<Marks
|
||||||
className={`${prefixCls}-mark`}
|
{...markProps}
|
||||||
onClickLabel={disabled ? noop : this.onClickMarkLabel}
|
|
||||||
vertical={vertical}
|
|
||||||
marks={marks}
|
|
||||||
included={included}
|
|
||||||
lowerBound={this.getLowerBound()}
|
|
||||||
upperBound={this.getUpperBound()}
|
|
||||||
max={max}
|
|
||||||
min={min}
|
|
||||||
/>
|
/>
|
||||||
{children}
|
{this.$slots.default}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,91 @@
|
||||||
import React from 'react';
|
import PropTypes from '../../../_util/vue-types'
|
||||||
import PropTypes from 'prop-types';
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
import Tooltip from 'rc-tooltip';
|
import Tooltip from '../../vc-tooltip'
|
||||||
import Handle from './Handle';
|
import Handle from './Handle'
|
||||||
|
|
||||||
export default function createSliderWithTooltip(Component) {
|
export default function createSliderWithTooltip (Component) {
|
||||||
return class ComponentWrapper extends React.Component {
|
return {
|
||||||
static propTypes = {
|
mixins: [BaseMixin],
|
||||||
tipFormatter: PropTypes.func,
|
props: {
|
||||||
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
tipFormatter: PropTypes.func.def((value) => { return value }),
|
||||||
tipProps: PropTypes.object,
|
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]).def([{}]),
|
||||||
};
|
tipProps: PropTypes.object.def({}),
|
||||||
static defaultProps = {
|
},
|
||||||
tipFormatter(value) { return value; },
|
data () {
|
||||||
handleStyle: [{}],
|
return {
|
||||||
tipProps: {},
|
visibles: {},
|
||||||
};
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = { visibles: {} };
|
|
||||||
}
|
|
||||||
handleTooltipVisibleChange = (index, visible) => {
|
|
||||||
this.setState((prevState) => {
|
|
||||||
return {
|
|
||||||
visibles: {
|
|
||||||
...prevState.visibles,
|
|
||||||
[index]: visible,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
handleWithTooltip = ({ value, dragging, index, disabled, ...restProps }) => {
|
|
||||||
const {
|
|
||||||
tipFormatter,
|
|
||||||
tipProps,
|
|
||||||
handleStyle,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
prefixCls = 'rc-slider-tooltip',
|
|
||||||
overlay = tipFormatter(value),
|
|
||||||
placement = 'top',
|
|
||||||
visible = visible || false,
|
|
||||||
...restTooltipProps,
|
|
||||||
} = tipProps;
|
|
||||||
|
|
||||||
let handleStyleWithIndex;
|
|
||||||
if (Array.isArray(handleStyle)) {
|
|
||||||
handleStyleWithIndex = handleStyle[index] || handleStyle[0];
|
|
||||||
} else {
|
|
||||||
handleStyleWithIndex = handleStyle;
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTooltipVisibleChange (index, visible) {
|
||||||
|
this.setState((prevState) => {
|
||||||
|
return {
|
||||||
|
visibles: {
|
||||||
|
...prevState.visibles,
|
||||||
|
[index]: visible,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleWithTooltip ({ value, dragging, index, disabled, ...restProps }) {
|
||||||
|
const {
|
||||||
|
tipFormatter,
|
||||||
|
tipProps,
|
||||||
|
handleStyle,
|
||||||
|
} = this.$props
|
||||||
|
|
||||||
return (
|
const {
|
||||||
<Tooltip
|
prefixCls = 'rc-slider-tooltip',
|
||||||
{...restTooltipProps}
|
overlay = tipFormatter(value),
|
||||||
prefixCls={prefixCls}
|
placement = 'top',
|
||||||
overlay={overlay}
|
visible = visible || false,
|
||||||
placement={placement}
|
...restTooltipProps } = tipProps
|
||||||
visible={(!disabled && (this.state.visibles[index] || dragging)) || visible}
|
|
||||||
key={index}
|
|
||||||
>
|
|
||||||
|
|
||||||
<Handle
|
let handleStyleWithIndex
|
||||||
{...restProps}
|
if (Array.isArray(handleStyle)) {
|
||||||
style={{
|
handleStyleWithIndex = handleStyle[index] || handleStyle[0]
|
||||||
...handleStyleWithIndex,
|
} else {
|
||||||
}}
|
handleStyleWithIndex = handleStyle
|
||||||
value={value}
|
}
|
||||||
onMouseEnter={() => this.handleTooltipVisibleChange(index, true)}
|
|
||||||
onMouseLeave={() => this.handleTooltipVisibleChange(index, false)}
|
const tooltipProps = {
|
||||||
/>
|
props: {
|
||||||
</Tooltip>
|
prefixCls,
|
||||||
);
|
overlay,
|
||||||
}
|
placement,
|
||||||
render() {
|
visible: (!disabled && (this.visibles[index] || dragging)) || visible,
|
||||||
return <Component {...this.props} handle={this.handleWithTooltip} />;
|
...restTooltipProps,
|
||||||
}
|
},
|
||||||
};
|
key: index,
|
||||||
|
}
|
||||||
|
const handleProps = {
|
||||||
|
props: {
|
||||||
|
value,
|
||||||
|
...restProps,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
mouseenter: () => this.handleTooltipVisibleChange(index, true),
|
||||||
|
mouseleave: () => this.handleTooltipVisibleChange(index, false),
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
...handleStyleWithIndex,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
{...tooltipProps}
|
||||||
|
>
|
||||||
|
|
||||||
|
<Handle
|
||||||
|
{...handleProps}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
return <Component {...this.$props} handle={this.handleWithTooltip} />
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { findDOMNode } from 'react-dom'
|
|
||||||
import keyCode from '../../_util/KeyCode'
|
import keyCode from '../../_util/KeyCode'
|
||||||
|
|
||||||
export function isEventFromHandle (e, handles) {
|
export function isEventFromHandle (e, handles) {
|
||||||
return Object.keys(handles)
|
return Object.keys(handles)
|
||||||
.some(key => e.target === findDOMNode(handles[key]))
|
.some(key => e.target === handles[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValueOutOfRange (value, { min, max }) {
|
export function isValueOutOfRange (value, { min, max }) {
|
||||||
|
|
Loading…
Reference in New Issue