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