refactor: slider
parent
0535f09edf
commit
db6acc5199
|
@ -3,6 +3,7 @@ import classNames from '../classNames';
|
|||
import { isVNode, Fragment, Comment, Text, h } from 'vue';
|
||||
import { camelize, hyphenate, isOn, resolvePropValue } from '../util';
|
||||
import isValid from '../isValid';
|
||||
import initDefaultProps from './initDefaultProps';
|
||||
// function getType(fn) {
|
||||
// const match = fn && fn.toString().match(/^\s*function (\w+)/);
|
||||
// return match ? match[1] : '';
|
||||
|
@ -367,16 +368,6 @@ export function filterEmpty(children = []) {
|
|||
});
|
||||
return res.filter(c => !isEmptyElement(c));
|
||||
}
|
||||
const initDefaultProps = (propTypes, defaultProps) => {
|
||||
Object.keys(defaultProps).forEach(k => {
|
||||
if (propTypes[k]) {
|
||||
propTypes[k].def && (propTypes[k] = propTypes[k].def(defaultProps[k]));
|
||||
} else {
|
||||
throw new Error(`not have ${k} prop`);
|
||||
}
|
||||
});
|
||||
return propTypes;
|
||||
};
|
||||
|
||||
export function mergeProps() {
|
||||
const args = [].slice.call(arguments, 0);
|
||||
|
@ -401,7 +392,6 @@ function isValidElement(element) {
|
|||
function getPropsSlot(slots, props, prop = 'default') {
|
||||
return props[prop] ?? slots[prop]?.();
|
||||
}
|
||||
|
||||
export {
|
||||
splitAttrs,
|
||||
hasProp,
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { onBeforeUnmount, watch } from 'vue';
|
||||
import { onActivated } from 'vue';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import Tooltip, { tooltipProps } from '../tooltip';
|
||||
import raf from '../_util/raf';
|
||||
|
||||
export default defineComponent({
|
||||
props: tooltipProps,
|
||||
name: 'SliderTooltip',
|
||||
inheritAttrs: false,
|
||||
setup(props, { attrs, slots }) {
|
||||
const innerRef = ref<any>(null);
|
||||
|
||||
const rafRef = ref<number | null>(null);
|
||||
|
||||
function cancelKeepAlign() {
|
||||
raf.cancel(rafRef.value!);
|
||||
rafRef.value = null;
|
||||
}
|
||||
|
||||
function keepAlign() {
|
||||
rafRef.value = raf(() => {
|
||||
innerRef.value?.forcePopupAlign();
|
||||
rafRef.value = null;
|
||||
});
|
||||
}
|
||||
const align = () => {
|
||||
cancelKeepAlign();
|
||||
if (props.visible) {
|
||||
keepAlign();
|
||||
}
|
||||
};
|
||||
watch(
|
||||
[() => props.visible, () => props.title],
|
||||
() => {
|
||||
align();
|
||||
},
|
||||
{ flush: 'post', immediate: true },
|
||||
);
|
||||
onActivated(() => {
|
||||
align();
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
cancelKeepAlign();
|
||||
});
|
||||
return () => {
|
||||
return <Tooltip ref={innerRef} {...props} {...attrs} v-slots={slots} />;
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,56 +1,76 @@
|
|||
import type { VNodeTypes } from 'vue';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { computed, CSSProperties, ref, VNodeTypes } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { getOptionProps } from '../_util/props-util';
|
||||
import VcSlider from '../vc-slider/src/Slider';
|
||||
import VcRange from '../vc-slider/src/Range';
|
||||
import VcHandle from '../vc-slider/src/Handle';
|
||||
import Tooltip from '../tooltip';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import abstractTooltipProps from '../tooltip/abstractTooltipProps';
|
||||
import { withInstall } from '../_util/type';
|
||||
import { VueNode, withInstall } from '../_util/type';
|
||||
import { PropType } from 'vue';
|
||||
import { TooltipPlacement } from '../tooltip/Tooltip';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import SliderTooltip from './SliderTooltip';
|
||||
import classNames from '../_util/classNames';
|
||||
|
||||
export type SliderValue = number | [number, number];
|
||||
|
||||
interface HandleGeneratorInfo {
|
||||
value: number;
|
||||
dragging: boolean;
|
||||
index: number;
|
||||
rest: any[];
|
||||
interface SliderMarks {
|
||||
[key: number]:
|
||||
| VueNode
|
||||
| {
|
||||
style: CSSProperties;
|
||||
label: any;
|
||||
};
|
||||
}
|
||||
|
||||
interface HandleGeneratorInfo {
|
||||
value?: number;
|
||||
dragging?: boolean;
|
||||
index: number;
|
||||
rest?: any[];
|
||||
}
|
||||
interface SliderRange {
|
||||
draggableTrack?: boolean;
|
||||
}
|
||||
export type HandleGeneratorFn = (config: {
|
||||
tooltipPrefixCls?: string;
|
||||
prefixCls?: string;
|
||||
info: HandleGeneratorInfo;
|
||||
}) => VNodeTypes;
|
||||
type Value = [number, number] | number;
|
||||
|
||||
const tooltipProps = abstractTooltipProps();
|
||||
const defaultTipFormatter = (value: number) => (typeof value === 'number' ? value.toString() : '');
|
||||
export const SliderProps = () => ({
|
||||
prefixCls: PropTypes.string,
|
||||
tooltipPrefixCls: PropTypes.string,
|
||||
range: PropTypes.looseBool,
|
||||
reverse: PropTypes.looseBool,
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
step: PropTypes.any,
|
||||
marks: PropTypes.object,
|
||||
dots: PropTypes.looseBool,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.arrayOf(PropTypes.number)]),
|
||||
defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.arrayOf(PropTypes.number)]),
|
||||
included: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
vertical: PropTypes.looseBool,
|
||||
tipFormatter: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
||||
tooltipVisible: PropTypes.looseBool,
|
||||
tooltipPlacement: tooltipProps.placement,
|
||||
getTooltipPopupContainer: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
onAfterChange: PropTypes.func,
|
||||
prefixCls: String,
|
||||
tooltipPrefixCls: String,
|
||||
range: { type: [Boolean, Object] as PropType<boolean | SliderRange>, default: undefined },
|
||||
reverse: { type: Boolean, default: undefined },
|
||||
min: Number,
|
||||
max: Number,
|
||||
step: { type: [Number, Object] as PropType<null | number> },
|
||||
marks: { type: Object as PropType<SliderMarks> },
|
||||
dots: { type: Boolean, default: undefined },
|
||||
value: { type: [Number, Array] as PropType<Value> },
|
||||
defaultValue: { type: [Number, Array] as PropType<Value> },
|
||||
included: { type: Boolean, default: undefined },
|
||||
disabled: { type: Boolean, default: undefined },
|
||||
vertical: { type: Boolean, default: undefined },
|
||||
tipFormatter: {
|
||||
type: Function as PropType<(value?: number) => any>,
|
||||
default: defaultTipFormatter,
|
||||
},
|
||||
tooltipVisible: { type: Boolean, default: undefined },
|
||||
tooltipPlacement: { type: String as PropType<TooltipPlacement> },
|
||||
getTooltipPopupContainer: {
|
||||
type: Function as PropType<(triggerNode: HTMLElement) => HTMLElement>,
|
||||
},
|
||||
autofocus: { type: Boolean, default: undefined },
|
||||
onChange: { type: Function as PropType<(value: Value) => void> },
|
||||
onAfterChange: { type: Function as PropType<(value: Value) => void> },
|
||||
handleStyle: { type: [Object, Array] as PropType<CSSProperties[] | CSSProperties> },
|
||||
trackStyle: { type: [Object, Array] as PropType<CSSProperties[] | CSSProperties> },
|
||||
});
|
||||
|
||||
const defaultTipFormatter = (value: number) => value.toString();
|
||||
export type Visibles = { [index: number]: boolean };
|
||||
|
||||
const Slider = defineComponent({
|
||||
name: 'ASlider',
|
||||
|
@ -59,109 +79,125 @@ const Slider = defineComponent({
|
|||
props: {
|
||||
...SliderProps(),
|
||||
},
|
||||
emits: ['update:value', 'change'],
|
||||
setup() {
|
||||
return {
|
||||
vcSlider: null,
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
emits: ['update:value', 'change', 'afterChange'],
|
||||
slots: ['mark'],
|
||||
setup(props, { attrs, slots, emit, expose }) {
|
||||
const { prefixCls, rootPrefixCls, direction, getPopupContainer, configProvider } =
|
||||
useConfigInject('slider', props);
|
||||
const sliderRef = ref();
|
||||
const visibles = ref<Visibles>({});
|
||||
const toggleTooltipVisible = (index: number, visible: boolean) => {
|
||||
visibles.value[index] = visible;
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visibles: {},
|
||||
const tooltipPlacement = computed(() => {
|
||||
if (props.tooltipPlacement) {
|
||||
return props.tooltipPlacement;
|
||||
}
|
||||
if (!props.vertical) {
|
||||
return 'top';
|
||||
}
|
||||
return direction.value === 'rtl' ? 'left' : 'right';
|
||||
});
|
||||
|
||||
const focus = () => {
|
||||
sliderRef.value?.focus();
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleTooltipVisible(index: number, visible: boolean) {
|
||||
this.setState(({ visibles }) => ({
|
||||
visibles: {
|
||||
...visibles,
|
||||
[index]: visible,
|
||||
},
|
||||
}));
|
||||
},
|
||||
handleWithTooltip(
|
||||
tooltipPrefixCls: string,
|
||||
prefixCls: string,
|
||||
{ value, dragging, index, ...restProps }: HandleGeneratorInfo,
|
||||
): VNodeTypes {
|
||||
const {
|
||||
tipFormatter = defaultTipFormatter,
|
||||
tooltipVisible,
|
||||
tooltipPlacement,
|
||||
getTooltipPopupContainer,
|
||||
} = this.$props;
|
||||
const { visibles } = this;
|
||||
const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
|
||||
const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
|
||||
const tooltipProps = {
|
||||
prefixCls: tooltipPrefixCls,
|
||||
title: tipFormatter ? tipFormatter(value) : '',
|
||||
visible,
|
||||
placement: tooltipPlacement || 'top',
|
||||
transitionName: 'zoom-down',
|
||||
overlayClassName: `${prefixCls}-tooltip`,
|
||||
getPopupContainer: getTooltipPopupContainer || (() => document.body),
|
||||
key: index,
|
||||
};
|
||||
const handleProps = {
|
||||
value,
|
||||
...restProps,
|
||||
onMouseenter: () => this.toggleTooltipVisible(index, true),
|
||||
onMouseleave: () => this.toggleTooltipVisible(index, false),
|
||||
};
|
||||
return (
|
||||
<Tooltip {...tooltipProps}>
|
||||
<VcHandle {...handleProps} />
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
saveSlider(node: any) {
|
||||
this.vcSlider = node;
|
||||
},
|
||||
focus() {
|
||||
this.vcSlider.focus();
|
||||
},
|
||||
blur() {
|
||||
this.vcSlider.blur();
|
||||
},
|
||||
handleChange(val: SliderValue) {
|
||||
this.$emit('update:value', val);
|
||||
this.$emit('change', val);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
range,
|
||||
prefixCls: customizePrefixCls,
|
||||
tooltipPrefixCls: customizeTooltipPrefixCls,
|
||||
...restProps
|
||||
} = { ...getOptionProps(this), ...this.$attrs } as any;
|
||||
const { getPrefixCls } = this.configProvider;
|
||||
const prefixCls = getPrefixCls('slider', customizePrefixCls);
|
||||
const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
|
||||
if (range) {
|
||||
const vcRangeProps = {
|
||||
...restProps,
|
||||
prefixCls,
|
||||
tooltipPrefixCls,
|
||||
handle: (info: HandleGeneratorInfo) =>
|
||||
this.handleWithTooltip(tooltipPrefixCls, prefixCls, info),
|
||||
ref: this.saveSlider,
|
||||
onChange: this.handleChange,
|
||||
};
|
||||
return <VcRange {...vcRangeProps} />;
|
||||
}
|
||||
const vcSliderProps = {
|
||||
...restProps,
|
||||
prefixCls,
|
||||
const blur = () => {
|
||||
sliderRef.value?.blur();
|
||||
};
|
||||
const handleChange = (val: SliderValue) => {
|
||||
emit('update:value', val);
|
||||
emit('change', val);
|
||||
};
|
||||
expose({
|
||||
focus,
|
||||
blur,
|
||||
});
|
||||
const handleWithTooltip: HandleGeneratorFn = ({
|
||||
tooltipPrefixCls,
|
||||
handle: (info: HandleGeneratorInfo) =>
|
||||
this.handleWithTooltip(tooltipPrefixCls, prefixCls, info),
|
||||
ref: this.saveSlider,
|
||||
onChange: this.handleChange,
|
||||
info: { value, dragging, index, ...restProps },
|
||||
}) => {
|
||||
const { tipFormatter, tooltipVisible, getTooltipPopupContainer } = props;
|
||||
const isTipFormatter = tipFormatter ? visibles.value[index] || dragging : false;
|
||||
const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
|
||||
return (
|
||||
<SliderTooltip
|
||||
prefixCls={tooltipPrefixCls}
|
||||
title={tipFormatter ? tipFormatter(value) : ''}
|
||||
visible={visible}
|
||||
placement={tooltipPlacement.value}
|
||||
transitionName={`${rootPrefixCls.value}-zoom-down`}
|
||||
key={index}
|
||||
overlayClassName={`${prefixCls.value}-tooltip`}
|
||||
getPopupContainer={getTooltipPopupContainer || getPopupContainer.value}
|
||||
>
|
||||
<VcHandle
|
||||
{...restProps}
|
||||
value={value}
|
||||
onMouseenter={() => toggleTooltipVisible(index, true)}
|
||||
onMouseleave={() => toggleTooltipVisible(index, false)}
|
||||
/>
|
||||
</SliderTooltip>
|
||||
);
|
||||
};
|
||||
return () => {
|
||||
const { tooltipPrefixCls: customizeTooltipPrefixCls, range, ...restProps } = props;
|
||||
const tooltipPrefixCls = configProvider.getPrefixCls('tooltip', customizeTooltipPrefixCls);
|
||||
const cls = classNames(attrs.class, {
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
});
|
||||
|
||||
// make reverse default on rtl direction
|
||||
if (direction.value === 'rtl' && !restProps.vertical) {
|
||||
restProps.reverse = !restProps.reverse;
|
||||
}
|
||||
|
||||
// extrack draggableTrack from range={{ ... }}
|
||||
let draggableTrack: boolean | undefined;
|
||||
if (typeof range === 'object') {
|
||||
draggableTrack = range.draggableTrack;
|
||||
}
|
||||
|
||||
if (range) {
|
||||
return (
|
||||
<VcRange
|
||||
{...restProps}
|
||||
step={restProps.step!}
|
||||
draggableTrack={draggableTrack}
|
||||
class={cls}
|
||||
ref={ref}
|
||||
handle={(info: HandleGeneratorInfo) =>
|
||||
handleWithTooltip({
|
||||
tooltipPrefixCls,
|
||||
prefixCls: prefixCls.value,
|
||||
info,
|
||||
})
|
||||
}
|
||||
prefixCls={prefixCls.value}
|
||||
onChange={handleChange}
|
||||
v-slots={{ mark: slots.mark }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<VcSlider
|
||||
{...restProps}
|
||||
step={restProps.step!}
|
||||
class={cls}
|
||||
ref={ref}
|
||||
handle={(info: HandleGeneratorInfo) =>
|
||||
handleWithTooltip({
|
||||
tooltipPrefixCls,
|
||||
prefixCls: prefixCls.value,
|
||||
info,
|
||||
})
|
||||
}
|
||||
prefixCls={prefixCls.value}
|
||||
onChange={handleChange}
|
||||
v-slots={{ mark: slots.mark }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
return <VcSlider {...vcSliderProps} />;
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@slider-prefix-cls: ~'@{ant-prefix}-slider';
|
||||
|
||||
.@{slider-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&-mark {
|
||||
.@{slider-prefix-cls}-rtl & {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-dot {
|
||||
.@{slider-prefix-cls}-rtl & {
|
||||
margin-right: -4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.@{slider-prefix-cls}-rtl & {
|
||||
margin-right: -4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.@{slider-prefix-cls}-rtl & {
|
||||
margin-right: -4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vertical() {
|
||||
&-vertical {
|
||||
.@{slider-prefix-cls}-handle {
|
||||
.@{slider-prefix-cls}-rtl& {
|
||||
margin-right: -5px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.@{slider-prefix-cls}-mark {
|
||||
.@{slider-prefix-cls}-rtl& {
|
||||
right: 12px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.@{slider-prefix-cls}-mark-text {
|
||||
.@{slider-prefix-cls}-rtl& {
|
||||
right: 4px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.@{slider-prefix-cls}-dot {
|
||||
.@{slider-prefix-cls}-rtl& {
|
||||
right: 2px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import getPlacements, { AdjustOverflow, PlacementsConfig } from './placements';
|
|||
|
||||
export { AdjustOverflow, PlacementsConfig };
|
||||
|
||||
export type TooltipPlacement = typeof placementTypes;
|
||||
export type TooltipPlacement = typeof placementTypes[number];
|
||||
|
||||
// https://github.com/react-component/tooltip
|
||||
// https://github.com/yiminghe/dom-align
|
||||
|
@ -44,7 +44,7 @@ const props = abstractTooltipProps();
|
|||
|
||||
const PresetColorRegex = new RegExp(`^(${PresetColorTypes.join('|')})(-inverse)?$`);
|
||||
|
||||
const tooltipProps = {
|
||||
export const tooltipProps = {
|
||||
...props,
|
||||
title: PropTypes.VNodeChild,
|
||||
};
|
||||
|
@ -88,8 +88,11 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const handleVisibleChange = (val: boolean) => {
|
||||
visible.value = isNoTitle() ? false : val;
|
||||
if (!isNoTitle()) {
|
||||
const noTitle = isNoTitle();
|
||||
if (props.visible === undefined) {
|
||||
visible.value = noTitle ? false : val;
|
||||
}
|
||||
if (!noTitle) {
|
||||
emit('update:visible', val);
|
||||
emit('visibleChange', val);
|
||||
}
|
||||
|
@ -99,7 +102,7 @@ export default defineComponent({
|
|||
return tooltip.value.getPopupDomNode();
|
||||
};
|
||||
|
||||
expose({ getPopupDomNode, visible });
|
||||
expose({ getPopupDomNode, visible, forcePopupAlign: () => tooltip.value?.forcePopupAlign() });
|
||||
|
||||
const tooltipPlacements = computed(() => {
|
||||
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = props;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { withInstall } from '../_util/type';
|
||||
import ToolTip from './Tooltip';
|
||||
import ToolTip, { tooltipProps } from './Tooltip';
|
||||
|
||||
export type {
|
||||
TooltipProps,
|
||||
|
@ -9,4 +9,6 @@ export type {
|
|||
PlacementTypes,
|
||||
} from './Tooltip';
|
||||
|
||||
export { tooltipProps };
|
||||
|
||||
export default withInstall(ToolTip);
|
||||
|
|
|
@ -19,6 +19,9 @@ export default defineComponent({
|
|||
value: PropTypes.number,
|
||||
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
reverse: PropTypes.looseBool,
|
||||
ariaLabel: String,
|
||||
ariaLabelledBy: String,
|
||||
ariaValueTextFormatter: Function,
|
||||
// handleFocus: PropTypes.func.def(noop),
|
||||
// handleBlur: PropTypes.func.def(noop),
|
||||
},
|
||||
|
@ -68,13 +71,26 @@ export default defineComponent({
|
|||
},
|
||||
// when click can not focus in vue, use mousedown trigger focus
|
||||
handleMousedown(e) {
|
||||
e.preventDefault();
|
||||
this.focus();
|
||||
this.__emit('mousedown', e);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const { prefixCls, vertical, reverse, offset, disabled, min, max, value, tabindex } =
|
||||
getOptionProps(this);
|
||||
const {
|
||||
prefixCls,
|
||||
vertical,
|
||||
reverse,
|
||||
offset,
|
||||
disabled,
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
tabindex,
|
||||
ariaLabel,
|
||||
ariaLabelledBy,
|
||||
ariaValueTextFormatter,
|
||||
} = getOptionProps(this);
|
||||
const className = classNames(this.$attrs.class, {
|
||||
[`${prefixCls}-handle-click-focused`]: this.clickFocused,
|
||||
});
|
||||
|
@ -83,7 +99,7 @@ export default defineComponent({
|
|||
? {
|
||||
[reverse ? 'top' : 'bottom']: `${offset}%`,
|
||||
[reverse ? 'bottom' : 'top']: 'auto',
|
||||
transform: `translateY(+50%)`,
|
||||
transform: reverse ? null : `translateY(+50%)`,
|
||||
}
|
||||
: {
|
||||
[reverse ? 'right' : 'left']: `${offset}%`,
|
||||
|
@ -101,15 +117,20 @@ export default defineComponent({
|
|||
...this.$attrs.style,
|
||||
...positionStyle,
|
||||
};
|
||||
let _tabIndex = tabindex || 0;
|
||||
let mergedTabIndex = tabindex || 0;
|
||||
if (disabled || tabindex === null) {
|
||||
_tabIndex = null;
|
||||
mergedTabIndex = null;
|
||||
}
|
||||
|
||||
let ariaValueText;
|
||||
if (ariaValueTextFormatter) {
|
||||
ariaValueText = ariaValueTextFormatter(value);
|
||||
}
|
||||
|
||||
const handleProps = {
|
||||
...this.$attrs,
|
||||
role: 'slider',
|
||||
tabindex: _tabIndex,
|
||||
tabindex: mergedTabIndex,
|
||||
...ariaProps,
|
||||
class: className,
|
||||
onBlur: this.handleBlur,
|
||||
|
@ -118,6 +139,13 @@ export default defineComponent({
|
|||
ref: this.setHandleRef,
|
||||
style: elStyle,
|
||||
};
|
||||
return <div {...handleProps} />;
|
||||
return (
|
||||
<div
|
||||
{...handleProps}
|
||||
aria-label={ariaLabel}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
aria-valuetext={ariaValueText}
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import classNames from '../../_util/classNames';
|
||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
||||
import BaseMixin from '../../_util/BaseMixin';
|
||||
import { initDefaultProps, hasProp } from '../../_util/props-util';
|
||||
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';
|
||||
|
||||
const trimAlignValue = ({ value, handle, bounds, props }) => {
|
||||
const { allowCross, pushable } = props;
|
||||
|
@ -35,6 +36,10 @@ const rangeProps = {
|
|||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
autofocus: PropTypes.looseBool,
|
||||
ariaLabelGroupForHandles: Array,
|
||||
ariaLabelledByGroupForHandles: Array,
|
||||
ariaValueTextFormatterGroupForHandles: Array,
|
||||
draggableTrack: PropTypes.looseBool,
|
||||
};
|
||||
const Range = {
|
||||
name: 'Range',
|
||||
|
@ -46,6 +51,10 @@ const Range = {
|
|||
allowCross: true,
|
||||
pushable: false,
|
||||
tabindex: [],
|
||||
draggableTrack: false,
|
||||
ariaLabelGroupForHandles: [],
|
||||
ariaLabelledByGroupForHandles: [],
|
||||
ariaValueTextFormatterGroupForHandles: [],
|
||||
}),
|
||||
data() {
|
||||
const { count, min, max } = this;
|
||||
|
@ -89,7 +98,7 @@ const Range = {
|
|||
methods: {
|
||||
setChangeValue(value) {
|
||||
const { bounds } = this;
|
||||
const nextBounds = value.map((v, i) =>
|
||||
let nextBounds = value.map((v, i) =>
|
||||
trimAlignValue({
|
||||
value: v,
|
||||
handle: i,
|
||||
|
@ -97,8 +106,19 @@ const Range = {
|
|||
props: this.$props,
|
||||
}),
|
||||
);
|
||||
if (nextBounds.length === bounds.length && nextBounds.every((v, i) => v === bounds[i]))
|
||||
return;
|
||||
if (bounds.length === nextBounds.length) {
|
||||
if (nextBounds.every((v, i) => v === bounds[i])) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
nextBounds = value.map((v, i) =>
|
||||
trimAlignValue({
|
||||
value: v,
|
||||
handle: i,
|
||||
props: this.$props,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
this.setState({ bounds: nextBounds });
|
||||
|
||||
|
@ -131,6 +151,19 @@ const Range = {
|
|||
const changedValue = data.bounds;
|
||||
this.__emit('change', changedValue);
|
||||
},
|
||||
|
||||
positionGetValue(position) {
|
||||
const bounds = this.getValue();
|
||||
const value = this.calcValueByPos(position);
|
||||
const closestBound = this.getClosestBound(value);
|
||||
const index = this.getBoundNeedMoving(value, closestBound);
|
||||
const prevValue = bounds[index];
|
||||
if (value === prevValue) return null;
|
||||
|
||||
const nextBounds = [...bounds];
|
||||
nextBounds[index] = value;
|
||||
return nextBounds;
|
||||
},
|
||||
onStart(position) {
|
||||
const { bounds } = this;
|
||||
this.__emit('beforeChange', bounds);
|
||||
|
@ -156,13 +189,35 @@ const Range = {
|
|||
onEnd(force) {
|
||||
const { sHandle } = this;
|
||||
this.removeDocumentEvents();
|
||||
if (!sHandle) {
|
||||
this.dragTrack = false;
|
||||
}
|
||||
if (sHandle !== null || force) {
|
||||
this.__emit('afterChange', this.bounds);
|
||||
}
|
||||
this.setState({ sHandle: null });
|
||||
},
|
||||
onMove(e, position) {
|
||||
onMove(e, position, dragTrack, startBounds) {
|
||||
utils.pauseEvent(e);
|
||||
const { $data: state, $props: props } = this;
|
||||
const maxValue = props.max || 100;
|
||||
const minValue = props.min || 0;
|
||||
if (dragTrack) {
|
||||
let pos = props.vertical ? -position : position;
|
||||
pos = props.reverse ? -pos : pos;
|
||||
const max = maxValue - Math.max(...startBounds);
|
||||
const min = minValue - Math.min(...startBounds);
|
||||
const ratio = Math.min(Math.max(pos / (this.getSliderLength() / 100), min), max);
|
||||
const nextBounds = startBounds.map(v =>
|
||||
Math.floor(Math.max(Math.min(v + ratio, maxValue), minValue)),
|
||||
);
|
||||
if (state.bounds.map((c, i) => c === nextBounds[i]).some(c => !c)) {
|
||||
this.onChange({
|
||||
bounds: nextBounds,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
const { bounds, sHandle } = this;
|
||||
const value = this.calcValueByPos(position);
|
||||
const oldValue = bounds[sHandle];
|
||||
|
@ -193,8 +248,8 @@ const Range = {
|
|||
getClosestBound(value) {
|
||||
const { bounds } = this;
|
||||
let closestBound = 0;
|
||||
for (let i = 1; i < bounds.length - 1; ++i) {
|
||||
if (value > bounds[i]) {
|
||||
for (let i = 1; i < bounds.length - 1; i += 1) {
|
||||
if (value >= bounds[i]) {
|
||||
closestBound = i;
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +285,7 @@ const Range = {
|
|||
*/
|
||||
getPoints() {
|
||||
const { marks, step, min, max } = this;
|
||||
const cache = this._getPointsCache;
|
||||
const cache = this.internalPointsCache;
|
||||
if (!cache || cache.marks !== marks || cache.step !== step) {
|
||||
const pointsObject = { ...marks };
|
||||
if (step !== null) {
|
||||
|
@ -240,9 +295,9 @@ const Range = {
|
|||
}
|
||||
const points = Object.keys(pointsObject).map(parseFloat);
|
||||
points.sort((a, b) => a - b);
|
||||
this._getPointsCache = { marks, step, points };
|
||||
this.internalPointsCache = { marks, step, points };
|
||||
}
|
||||
return this._getPointsCache.points;
|
||||
return this.internalPointsCache.points;
|
||||
},
|
||||
|
||||
moveTo(value, isFromKeyboardEvent) {
|
||||
|
@ -277,8 +332,8 @@ const Range = {
|
|||
|
||||
pushSurroundingHandles(bounds, handle) {
|
||||
const value = bounds[handle];
|
||||
let { pushable: threshold } = this;
|
||||
threshold = Number(threshold);
|
||||
let { pushable } = this;
|
||||
const threshold = Number(pushable);
|
||||
|
||||
let direction = 0;
|
||||
if (bounds[handle + 1] - value < threshold) {
|
||||
|
@ -324,7 +379,8 @@ const Range = {
|
|||
}
|
||||
const nextHandle = handle + direction;
|
||||
const nextValue = points[nextPointIndex];
|
||||
const { pushable: threshold } = this;
|
||||
const { pushable } = this;
|
||||
const threshold = Number(pushable);
|
||||
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
|
||||
|
@ -397,28 +453,33 @@ const Range = {
|
|||
trackStyle,
|
||||
handleStyle,
|
||||
tabindex,
|
||||
ariaLabelGroupForHandles,
|
||||
ariaLabelledByGroupForHandles,
|
||||
ariaValueTextFormatterGroupForHandles,
|
||||
} = this;
|
||||
const handleGenerator = handle || defaultHandle;
|
||||
const offsets = bounds.map(v => this.calcOffset(v));
|
||||
|
||||
const handleClassName = `${prefixCls}-handle`;
|
||||
const handles = bounds.map((v, i) => {
|
||||
let _tabIndex = tabindex[i] || 0;
|
||||
let mergedTabIndex = tabindex[i] || 0;
|
||||
if (disabled || tabindex[i] === null) {
|
||||
_tabIndex = null;
|
||||
mergedTabIndex = null;
|
||||
}
|
||||
const dragging = sHandle === i;
|
||||
return handleGenerator({
|
||||
class: classNames({
|
||||
[handleClassName]: true,
|
||||
[`${handleClassName}-${i + 1}`]: true,
|
||||
[`${handleClassName}-dragging`]: dragging,
|
||||
}),
|
||||
prefixCls,
|
||||
vertical,
|
||||
dragging,
|
||||
offset: offsets[i],
|
||||
value: v,
|
||||
dragging: sHandle === i,
|
||||
index: i,
|
||||
tabindex: _tabIndex,
|
||||
tabindex: mergedTabIndex,
|
||||
min,
|
||||
max,
|
||||
reverse,
|
||||
|
@ -427,6 +488,9 @@ const Range = {
|
|||
ref: h => this.saveHandle(i, h),
|
||||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
ariaLabel: ariaLabelGroupForHandles[i],
|
||||
ariaLabelledBy: ariaLabelledByGroupForHandles[i],
|
||||
ariaValueTextFormatter: ariaValueTextFormatterGroupForHandles[i],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ const Slider = defineComponent({
|
|||
reverse: PropTypes.looseBool,
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
ariaLabelForHandle: String,
|
||||
ariaLabelledByForHandle: String,
|
||||
ariaValueTextFormatterForHandle: String,
|
||||
startPoint: Number,
|
||||
},
|
||||
data() {
|
||||
const defaultValue = this.defaultValue !== undefined ? this.defaultValue : this.min;
|
||||
|
@ -111,10 +115,14 @@ const Slider = defineComponent({
|
|||
}
|
||||
},
|
||||
getLowerBound() {
|
||||
return this.min;
|
||||
const minPoint = this.$props.startPoint || this.$props.min;
|
||||
return this.$data.sValue > minPoint ? minPoint : this.$data.sValue;
|
||||
},
|
||||
getUpperBound() {
|
||||
return this.sValue;
|
||||
if (this.$data.sValue < this.$props.startPoint) {
|
||||
return this.$props.startPoint;
|
||||
}
|
||||
return this.$data.sValue;
|
||||
},
|
||||
trimAlignValue(v, nextProps = {}) {
|
||||
if (v === null) {
|
||||
|
@ -124,18 +132,27 @@ const Slider = defineComponent({
|
|||
const val = utils.ensureValueInRange(v, mergedProps);
|
||||
return utils.ensureValuePrecision(val, mergedProps);
|
||||
},
|
||||
getTrack({ prefixCls, reverse, vertical, included, offset, minimumTrackStyle, _trackStyle }) {
|
||||
getTrack({
|
||||
prefixCls,
|
||||
reverse,
|
||||
vertical,
|
||||
included,
|
||||
minimumTrackStyle,
|
||||
mergedTrackStyle,
|
||||
length,
|
||||
offset,
|
||||
}) {
|
||||
return (
|
||||
<Track
|
||||
class={`${prefixCls}-track`}
|
||||
vertical={vertical}
|
||||
included={included}
|
||||
offset={0}
|
||||
offset={offset}
|
||||
reverse={reverse}
|
||||
length={offset}
|
||||
length={length}
|
||||
style={{
|
||||
...minimumTrackStyle,
|
||||
..._trackStyle,
|
||||
...mergedTrackStyle,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -150,8 +167,12 @@ const Slider = defineComponent({
|
|||
trackStyle,
|
||||
handleStyle,
|
||||
tabindex,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaValueTextFormatterForHandle,
|
||||
min,
|
||||
max,
|
||||
startPoint,
|
||||
reverse,
|
||||
handle,
|
||||
defaultHandle,
|
||||
|
@ -172,22 +193,26 @@ const Slider = defineComponent({
|
|||
reverse,
|
||||
index: 0,
|
||||
tabindex,
|
||||
ariaLabel: ariaLabelForHandle,
|
||||
ariaLabelledBy: ariaLabelledByForHandle,
|
||||
ariaValueTextFormatter: ariaValueTextFormatterForHandle,
|
||||
style: handleStyle[0] || handleStyle,
|
||||
ref: h => this.saveHandle(0, h),
|
||||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
});
|
||||
|
||||
const _trackStyle = trackStyle[0] || trackStyle;
|
||||
const trackOffset = startPoint !== undefined ? this.calcOffset(startPoint) : 0;
|
||||
const mergedTrackStyle = trackStyle[0] || trackStyle;
|
||||
return {
|
||||
tracks: this.getTrack({
|
||||
prefixCls,
|
||||
reverse,
|
||||
vertical,
|
||||
included,
|
||||
offset,
|
||||
offset: trackOffset,
|
||||
minimumTrackStyle,
|
||||
_trackStyle,
|
||||
mergedTrackStyle,
|
||||
length: offset - trackOffset,
|
||||
}),
|
||||
handles,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import supportsPassive from '../../../_util/supportsPassive';
|
|||
import classNames from '../../../_util/classNames';
|
||||
import { isValidElement } from '../../../_util/props-util';
|
||||
|
||||
const Marks = (_, { attrs }) => {
|
||||
const Marks = (_, { attrs, slots }) => {
|
||||
const {
|
||||
class: className,
|
||||
vertical,
|
||||
|
@ -16,19 +16,21 @@ const Marks = (_, { attrs }) => {
|
|||
onClickLabel,
|
||||
} = attrs;
|
||||
const marksKeys = Object.keys(marks);
|
||||
|
||||
const customMark = slots.mark;
|
||||
const range = max - min;
|
||||
const elements = marksKeys
|
||||
.map(parseFloat)
|
||||
.sort((a, b) => a - b)
|
||||
.map(point => {
|
||||
const markPoint = typeof marks[point] === 'function' ? marks[point](h) : marks[point];
|
||||
const markPoint = typeof marks[point] === 'function' ? marks[point]() : marks[point];
|
||||
const markPointIsObject = typeof markPoint === 'object' && !isValidElement(markPoint);
|
||||
const markLabel = markPointIsObject ? markPoint.label : markPoint;
|
||||
let markLabel = markPointIsObject ? markPoint.label : markPoint;
|
||||
if (!markLabel && markLabel !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (customMark) {
|
||||
markLabel = customMark({ point, label: markLabel });
|
||||
}
|
||||
const isActive =
|
||||
(!included && point === upperBound) ||
|
||||
(included && point <= upperBound && point >= lowerBound);
|
||||
|
@ -43,11 +45,9 @@ const Marks = (_, { attrs }) => {
|
|||
};
|
||||
|
||||
const leftStyle = {
|
||||
transform: `translateX(-50%)`,
|
||||
msTransform: `translateX(-50%)`,
|
||||
[reverse ? 'right' : 'left']: reverse
|
||||
? `${((point - min / 4) / range) * 100}%`
|
||||
: `${((point - min) / range) * 100}%`,
|
||||
transform: `translateX(${reverse ? `50%` : `-50%`})`,
|
||||
msTransform: `translateX(${reverse ? `50%` : `-50%`})`,
|
||||
[reverse ? 'right' : 'left']: `${((point - min) / range) * 100}%`,
|
||||
};
|
||||
|
||||
const style = vertical ? bottomStyle : leftStyle;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
/* eslint-disable */
|
||||
const Track = (_, { attrs }) => {
|
||||
const { included, vertical, offset, length, reverse, style, class: className } = attrs;
|
||||
|
||||
const { included, vertical, style, class: className } = attrs;
|
||||
let { length, offset, reverse } = attrs;
|
||||
if (length < 0) {
|
||||
reverse = !reverse;
|
||||
length = Math.abs(length);
|
||||
offset = 100 - offset;
|
||||
}
|
||||
const positonStyle = vertical
|
||||
? {
|
||||
[reverse ? 'top' : 'bottom']: `${offset}%`,
|
||||
|
|
|
@ -35,15 +35,13 @@ export default function createSlider(Component) {
|
|||
dotStyle: PropTypes.object,
|
||||
activeDotStyle: PropTypes.object,
|
||||
autofocus: PropTypes.looseBool,
|
||||
draggableTrack: PropTypes.looseBool,
|
||||
};
|
||||
return defineComponent({
|
||||
name: 'CreateSlider',
|
||||
mixins: [BaseMixin, Component],
|
||||
inheritAttrs: false,
|
||||
// model: {
|
||||
// prop: 'value',
|
||||
// event: 'change',
|
||||
// },
|
||||
slots: ['mark'],
|
||||
props: initDefaultProps(propTypes, {
|
||||
prefixCls: 'rc-slider',
|
||||
min: 0,
|
||||
|
@ -66,10 +64,7 @@ export default function createSlider(Component) {
|
|||
const isPointDiffEven = isFinite(max - min) ? (max - min) % step === 0 : true; // eslint-disable-line
|
||||
warning(
|
||||
step && Math.floor(step) === step ? isPointDiffEven : true,
|
||||
'Slider',
|
||||
'Slider[max] - Slider[min] (%s) should be a multiple of Slider[step] (%s)',
|
||||
max - min,
|
||||
step,
|
||||
`Slider[max] - Slider[min] (${max - min}) should be a multiple of Slider[step] (${step})`,
|
||||
);
|
||||
this.handlesRefs = {};
|
||||
return {};
|
||||
|
@ -105,43 +100,62 @@ export default function createSlider(Component) {
|
|||
};
|
||||
return <Handle {...handleProps} />;
|
||||
},
|
||||
onDown(e, position) {
|
||||
let p = position;
|
||||
const { draggableTrack, vertical: isVertical } = this.$props;
|
||||
const { bounds } = this.$data;
|
||||
|
||||
const value = draggableTrack && this.positionGetValue ? this.positionGetValue(p) || [] : [];
|
||||
|
||||
const inPoint = utils.isEventFromHandle(e, this.handlesRefs);
|
||||
this.dragTrack =
|
||||
draggableTrack &&
|
||||
bounds.length >= 2 &&
|
||||
!inPoint &&
|
||||
!value
|
||||
.map((n, i) => {
|
||||
const v = !i ? n >= bounds[i] : true;
|
||||
return i === value.length - 1 ? n <= bounds[i] : v;
|
||||
})
|
||||
.some(c => !c);
|
||||
|
||||
if (this.dragTrack) {
|
||||
this.dragOffset = p;
|
||||
this.startBounds = [...bounds];
|
||||
} else {
|
||||
if (!inPoint) {
|
||||
this.dragOffset = 0;
|
||||
} else {
|
||||
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target);
|
||||
this.dragOffset = p - handlePosition;
|
||||
p = handlePosition;
|
||||
}
|
||||
this.onStart(p);
|
||||
}
|
||||
},
|
||||
onMouseDown(e) {
|
||||
if (e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
const isVertical = this.vertical;
|
||||
let position = utils.getMousePosition(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.removeDocumentEvents();
|
||||
this.onStart(position);
|
||||
const isVertical = this.$props.vertical;
|
||||
const position = utils.getMousePosition(isVertical, e);
|
||||
this.onDown(e, position);
|
||||
this.addDocumentMouseEvents();
|
||||
utils.pauseEvent(e);
|
||||
},
|
||||
onTouchStart(e) {
|
||||
if (utils.isNotTouchEvent(e)) return;
|
||||
|
||||
const isVertical = this.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);
|
||||
const position = utils.getTouchPosition(isVertical, e);
|
||||
this.onDown(e, position);
|
||||
this.addDocumentTouchEvents();
|
||||
utils.pauseEvent(e);
|
||||
},
|
||||
onFocus(e) {
|
||||
const { vertical } = this;
|
||||
if (utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||
if (utils.isEventFromHandle(e, this.handlesRefs) && !this.dragTrack) {
|
||||
const handlePosition = utils.getHandleCenterPosition(vertical, e.target);
|
||||
this.dragOffset = 0;
|
||||
this.onStart(handlePosition);
|
||||
|
@ -150,7 +164,9 @@ export default function createSlider(Component) {
|
|||
}
|
||||
},
|
||||
onBlur(e) {
|
||||
this.onEnd();
|
||||
if (!this.dragTrack) {
|
||||
this.onEnd();
|
||||
}
|
||||
this.__emit('blur', e);
|
||||
},
|
||||
onMouseUp() {
|
||||
|
@ -164,7 +180,7 @@ export default function createSlider(Component) {
|
|||
return;
|
||||
}
|
||||
const position = utils.getMousePosition(this.vertical, e);
|
||||
this.onMove(e, position - this.dragOffset);
|
||||
this.onMove(e, position - this.dragOffset, this.dragTrack, this.startBounds);
|
||||
},
|
||||
onTouchMove(e) {
|
||||
if (utils.isNotTouchEvent(e) || !this.sliderRef) {
|
||||
|
@ -173,7 +189,7 @@ export default function createSlider(Component) {
|
|||
}
|
||||
|
||||
const position = utils.getTouchPosition(this.vertical, e);
|
||||
this.onMove(e, position - this.dragOffset);
|
||||
this.onMove(e, position - this.dragOffset, this.dragTrack, this.startBounds);
|
||||
},
|
||||
onKeyDown(e) {
|
||||
if (this.sliderRef && utils.isEventFromHandle(e, this.handlesRefs)) {
|
||||
|
@ -222,18 +238,19 @@ export default function createSlider(Component) {
|
|||
/* eslint-enable no-unused-expressions */
|
||||
},
|
||||
focus() {
|
||||
if (!this.disabled) {
|
||||
this.handlesRefs[0].focus();
|
||||
if (this.$props.disabled) {
|
||||
return;
|
||||
}
|
||||
this.handlesRefs[0]?.focus();
|
||||
},
|
||||
|
||||
blur() {
|
||||
if (!this.disabled) {
|
||||
Object.keys(this.handlesRefs).forEach(key => {
|
||||
if (this.handlesRefs[key] && this.handlesRefs[key].blur) {
|
||||
this.handlesRefs[key].blur();
|
||||
}
|
||||
});
|
||||
if (this.$props.disabled) {
|
||||
return;
|
||||
}
|
||||
Object.keys(this.handlesRefs).forEach(key => {
|
||||
this.handlesRefs[key]?.blur?.();
|
||||
});
|
||||
},
|
||||
calcValue(offset) {
|
||||
const { vertical, min, max } = this;
|
||||
|
@ -250,7 +267,7 @@ export default function createSlider(Component) {
|
|||
calcOffset(value) {
|
||||
const { min, max } = this;
|
||||
const ratio = (value - min) / (max - min);
|
||||
return ratio * 100;
|
||||
return Math.max(0, ratio * 100);
|
||||
},
|
||||
saveSlider(slider) {
|
||||
this.sliderRef = slider;
|
||||
|
@ -339,7 +356,7 @@ export default function createSlider(Component) {
|
|||
activeDotStyle={activeDotStyle}
|
||||
/>
|
||||
{handles}
|
||||
<Marks {...markProps} />
|
||||
<Marks {...markProps} v-slots={{ mark: this.$slots.mark }} />
|
||||
{getSlot(this)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function createSliderWithTooltip(Component) {
|
|||
}),
|
||||
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
|
||||
tipProps: PropTypes.object.def(() => ({})),
|
||||
getTooltipContainer: PropTypes.func.def(node => node.parentNode),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -34,7 +35,7 @@ export default function createSliderWithTooltip(Component) {
|
|||
});
|
||||
},
|
||||
handleWithTooltip({ value, dragging, index, disabled, ...restProps }) {
|
||||
const { tipFormatter, tipProps, handleStyle } = this.$props;
|
||||
const { tipFormatter, tipProps, handleStyle, getTooltipContainer } = this.$props;
|
||||
|
||||
const {
|
||||
prefixCls = 'rc-slider-tooltip',
|
||||
|
@ -53,6 +54,7 @@ export default function createSliderWithTooltip(Component) {
|
|||
|
||||
const tooltipProps = {
|
||||
...restTooltipProps,
|
||||
getTooltipContainer,
|
||||
prefixCls,
|
||||
overlay,
|
||||
placement,
|
||||
|
|
|
@ -22,8 +22,8 @@ export function isNotTouchEvent(e) {
|
|||
export function getClosestPoint(val, { marks, step, min, max }) {
|
||||
const points = Object.keys(marks).map(parseFloat);
|
||||
if (step !== null) {
|
||||
const base = 10 ** getPrecision(step);
|
||||
const maxSteps = Math.floor((max * base - min * base) / (step * base));
|
||||
const baseNum = 10 ** getPrecision(step);
|
||||
const maxSteps = Math.floor((max * baseNum - min * baseNum) / (step * baseNum));
|
||||
const steps = Math.min((val - min) / step, maxSteps);
|
||||
const closestStep = Math.round(steps) * step + min;
|
||||
points.push(closestStep);
|
||||
|
@ -96,7 +96,8 @@ export function calculateNextValue(func, value, props) {
|
|||
|
||||
if (props.step) {
|
||||
return operations[func](value, props.step);
|
||||
} else if (!!Object.keys(props.marks).length && !!props.marks[keyToGet]) {
|
||||
}
|
||||
if (!!Object.keys(props.marks).length && !!props.marks[keyToGet]) {
|
||||
return props.marks[keyToGet];
|
||||
}
|
||||
return value;
|
||||
|
|
|
@ -55,7 +55,11 @@ export default defineComponent({
|
|||
return triggerDOM.value.getPopupDomNode();
|
||||
};
|
||||
|
||||
expose({ getPopupDomNode, triggerDOM });
|
||||
expose({
|
||||
getPopupDomNode,
|
||||
triggerDOM,
|
||||
forcePopupAlign: () => triggerDOM.value?.forcePopupAlign(),
|
||||
});
|
||||
|
||||
const destroyTooltip = ref(false);
|
||||
const autoDestroy = ref(false);
|
||||
|
|
Loading…
Reference in New Issue