fix: Slider range exchange tooltip blink (#48536)

* fix: slider tooltip pos

* chore: clean up

* chore: fix style

* chore: bump rc-slider

* fix: lock clean up logic

* chore: finish

* test: update snapshot

* chore: bump rc-slider

* test: update snapshot

* test: test coverage

* chore: clean up
This commit is contained in:
二货爱吃白萝卜 2024-04-22 10:26:14 +08:00 committed by GitHub
parent ae155b97d5
commit c321492eeb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 348 additions and 311 deletions

View File

@ -70,25 +70,6 @@ Array [
style="left: 20%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -100,6 +81,11 @@ Array [
style="left: 50%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -114,9 +100,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>,
@ -215,25 +199,6 @@ Array [
style="left: 20%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -245,6 +210,11 @@ Array [
style="left: 50%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -259,9 +229,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>,
@ -340,25 +308,6 @@ Array [
style="bottom: 20%; transform: translateY(50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="vertical"
@ -370,6 +319,11 @@ Array [
style="bottom: 50%; transform: translateY(50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateY(50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -384,9 +338,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>
@ -435,25 +387,6 @@ Array [
style="bottom: 26%; transform: translateY(50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
26
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="vertical"
@ -465,6 +398,11 @@ Array [
style="bottom: 37%; transform: translateY(50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateY(50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -479,9 +417,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
37
</div>
/>
</div>
</div>
<div
@ -546,25 +482,6 @@ exports[`renders components/slider/demo/draggableTrack.tsx extend context correc
style="left: 20%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -576,6 +493,11 @@ exports[`renders components/slider/demo/draggableTrack.tsx extend context correc
style="left: 50%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -590,9 +512,7 @@ exports[`renders components/slider/demo/draggableTrack.tsx extend context correc
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>
@ -670,25 +590,6 @@ Array [
style="left: 20%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -700,6 +601,11 @@ Array [
style="left: 50%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -714,9 +620,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>,
@ -1237,25 +1141,6 @@ Array [
style="left: 26%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
26
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -1267,6 +1152,11 @@ Array [
style="left: 37%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -1281,9 +1171,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
37
</div>
/>
</div>
</div>
<div
@ -1633,25 +1521,6 @@ exports[`renders components/slider/demo/multiple.tsx extend context correctly 1`
style="left: 0%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
0
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -1663,25 +1532,6 @@ exports[`renders components/slider/demo/multiple.tsx extend context correctly 1`
style="left: 10%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
10
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -1693,6 +1543,11 @@ exports[`renders components/slider/demo/multiple.tsx extend context correctly 1`
style="left: 20%; transform: translateX(-50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(-50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -1707,9 +1562,7 @@ exports[`renders components/slider/demo/multiple.tsx extend context correctly 1`
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
/>
</div>
</div>
</div>
@ -1787,25 +1640,6 @@ Array [
style="right: 20%; transform: translateX(50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="horizontal"
@ -1817,6 +1651,11 @@ Array [
style="right: 50%; transform: translateX(50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateX(50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -1831,9 +1670,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>,
@ -2082,25 +1919,6 @@ Array [
style="bottom: 20%; transform: translateY(50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
20
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="vertical"
@ -2112,6 +1930,11 @@ Array [
style="bottom: 50%; transform: translateY(50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateY(50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -2126,9 +1949,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
50
</div>
/>
</div>
</div>
</div>
@ -2177,25 +1998,6 @@ Array [
style="bottom: 26%; transform: translateY(50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
26
</div>
</div>
</div>
<div
aria-disabled="false"
aria-orientation="vertical"
@ -2207,6 +2009,11 @@ Array [
style="bottom: 37%; transform: translateY(50%);"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="transform: translateY(50%); pointer-events: none; visibility: hidden;"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
@ -2221,9 +2028,7 @@ Array [
<div
class="ant-tooltip-inner"
role="tooltip"
>
37
</div>
/>
</div>
</div>
<div

View File

@ -62,6 +62,11 @@ Array [
style="left:50%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
</div>,
Disabled: ,
<button
@ -148,6 +153,11 @@ Array [
style="left:50%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
</div>,
<div
style="display:inline-block;height:300px;margin-left:70px"
@ -216,6 +226,11 @@ Array [
style="bottom:50%;transform:translateY(50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="bottom:NaN%;transform:translateY(50%);pointer-events:none;visibility:hidden"
/>
</div>
</div>,
<div
@ -273,6 +288,11 @@ Array [
style="bottom:37%;transform:translateY(50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="bottom:NaN%;transform:translateY(50%);pointer-events:none;visibility:hidden"
/>
<div
class="ant-slider-mark"
>
@ -344,6 +364,11 @@ exports[`renders components/slider/demo/draggableTrack.tsx correctly 1`] = `
style="left:50%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
</div>
`;
@ -409,6 +434,11 @@ Array [
style="left:50%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
</div>,
]
`;
@ -856,6 +886,11 @@ Array [
style="left:37%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
<div
class="ant-slider-mark"
>
@ -1166,6 +1201,11 @@ exports[`renders components/slider/demo/multiple.tsx correctly 1`] = `
style="left:20%;transform:translateX(-50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="left:NaN%;transform:translateX(-50%);pointer-events:none;visibility:hidden"
/>
</div>
`;
@ -1231,6 +1271,11 @@ Array [
style="right:50%;transform:translateX(50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="right:NaN%;transform:translateX(50%);pointer-events:none;visibility:hidden"
/>
</div>,
Reversed: ,
<button
@ -1380,6 +1425,11 @@ Array [
style="bottom:50%;transform:translateY(50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="bottom:NaN%;transform:translateY(50%);pointer-events:none;visibility:hidden"
/>
</div>
</div>,
<div
@ -1437,6 +1487,11 @@ Array [
style="bottom:37%;transform:translateY(50%)"
tabindex="0"
/>
<div
aria-hidden="true"
class="ant-slider-handle"
style="bottom:NaN%;transform:translateY(50%);pointer-events:none;visibility:hidden"
/>
<div
class="ant-slider-mark"
>

View File

@ -0,0 +1,56 @@
import React from 'react';
import Slider from '..';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import type { TooltipProps, TooltipRef } from '../../tooltip';
function tooltipProps(): TooltipProps {
return (global as any).tooltipProps;
}
jest.mock('../../tooltip', () => {
const ReactReal: typeof React = jest.requireActual('react');
const Tooltip = jest.requireActual('../../tooltip');
const TooltipComponent = Tooltip.default;
return ReactReal.forwardRef<TooltipRef, TooltipProps>((props, ref) => {
(global as any).tooltipProps = props;
return <TooltipComponent {...props} ref={ref} />;
});
});
describe('Slider.Tooltip', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
it('Correct show the tooltip', async () => {
const { container } = render(<Slider defaultValue={30} />);
const handleEle = container.querySelector('.ant-slider-handle')!;
// Enter
fireEvent.mouseEnter(handleEle);
await waitFakeTimer();
expect(tooltipProps().open).toBeTruthy();
// Down
fireEvent.mouseDown(handleEle);
await waitFakeTimer();
expect(tooltipProps().open).toBeTruthy();
// Move(Leave)
fireEvent.mouseLeave(handleEle);
await waitFakeTimer();
expect(tooltipProps().open).toBeTruthy();
// Up
fireEvent.mouseUp(handleEle);
await waitFakeTimer();
expect(tooltipProps().open).toBeFalsy();
});
});

View File

@ -2,7 +2,8 @@ import React from 'react';
import classNames from 'classnames';
import type { SliderProps as RcSliderProps } from 'rc-slider';
import RcSlider from 'rc-slider';
import type { SliderRef } from 'rc-slider/lib/Slider';
import type { SliderProps, SliderRef } from 'rc-slider/lib/Slider';
import raf from 'rc-util/lib/raf';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
@ -10,6 +11,7 @@ import DisabledContext from '../config-provider/DisabledContext';
import type { AbstractTooltipProps, TooltipPlacement } from '../tooltip';
import SliderTooltip from './SliderTooltip';
import useStyle from './style';
import useRafLock from './useRafLock';
export type SliderMarks = RcSliderProps['marks'];
@ -138,28 +140,57 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
tooltipVisible: legacyTooltipVisible,
getTooltipPopupContainer: legacyGetTooltipPopupContainer,
tooltipPlacement: legacyTooltipPlacement,
tooltip = {},
onChangeComplete,
...restProps
} = props;
const { vertical } = props;
const { direction, slider, getPrefixCls, getPopupContainer } = React.useContext(ConfigContext);
const contextDisabled = React.useContext(DisabledContext);
const mergedDisabled = disabled ?? contextDisabled;
const [opens, setOpens] = React.useState<Opens>({});
const toggleTooltipOpen = (index: number, open: boolean) => {
setOpens((prev: Opens) => ({ ...prev, [index]: open }));
// =============================== Open ===============================
const [hoverOpen, setHoverOpen] = useRafLock();
const [focusOpen, setFocusOpen] = useRafLock();
const activeOpen = hoverOpen || focusOpen;
const tooltipProps: SliderTooltipProps = {
...tooltip,
};
const {
open: tooltipOpen,
placement: tooltipPlacement,
getPopupContainer: getTooltipPopupContainer,
prefixCls: customizeTooltipPrefixCls,
formatter: tipFormatter,
} = tooltipProps;
const lockOpen = tooltipOpen ?? legacyTooltipVisible;
const mergedTipFormatter = getTipFormatter(tipFormatter, legacyTipFormatter);
// ============================= Change ==============================
const [dragging, setDragging] = useRafLock();
const onInternalChangeComplete: RcSliderProps['onChangeComplete'] = (nextValues) => {
onChangeComplete?.(nextValues as any);
setDragging(false);
};
const getTooltipPlacement = (placement?: TooltipPlacement, vertical?: boolean) => {
// ============================ Placement ============================
const getTooltipPlacement = (placement?: TooltipPlacement, vert?: boolean) => {
if (placement) {
return placement;
}
if (!vertical) {
if (!vert) {
return 'top';
}
return direction === 'rtl' ? 'left' : 'right';
};
// ============================== Style ===============================
const prefixCls = getPrefixCls('slider', customizePrefixCls);
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
@ -170,6 +201,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
rootClassName,
{
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-lock`]: dragging,
},
hashId,
cssVarCls,
@ -180,6 +212,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
restProps.reverse = !restProps.reverse;
}
// ============================= Multiple =============================
// Range config
const [mergedRange, draggableTrack] = React.useMemo(() => {
if (!range) {
@ -189,6 +222,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
return typeof range === 'object' ? [true, range.draggableTrack] : [true, false];
}, [range]);
// ============================= Warning ==============================
// Warning for deprecated usage
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Slider');
@ -204,60 +238,112 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
});
}
// ============================== Handle ==============================
React.useEffect(() => {
const onMouseUp = () => {
// Delay for 1 frame to make the click to enable hide tooltip
// even when the handle is focused
raf(() => {
setFocusOpen(false);
}, 1);
};
document.addEventListener('mouseup', onMouseUp);
return () => {
document.removeEventListener('mouseup', onMouseUp);
};
}, []);
const useActiveTooltipHandle = mergedRange && !lockOpen;
const handleRender: RcSliderProps['handleRender'] = (node, info) => {
const { index, dragging } = info;
const { index } = info;
const { tooltip = {}, vertical } = props;
const nodeProps = node.props;
const tooltipProps: SliderTooltipProps = {
...tooltip,
};
const {
open: tooltipOpen,
placement: tooltipPlacement,
getPopupContainer: getTooltipPopupContainer,
prefixCls: customizeTooltipPrefixCls,
formatter: tipFormatter,
} = tooltipProps;
const mergedTipFormatter = getTipFormatter(tipFormatter, legacyTipFormatter);
const isTipFormatter = mergedTipFormatter ? opens[index] || dragging : false;
const open =
tooltipOpen ?? legacyTooltipVisible ?? (tooltipOpen === undefined && isTipFormatter);
const passedProps = {
...node.props,
onMouseEnter: () => toggleTooltipOpen(index, true),
onMouseLeave: () => toggleTooltipOpen(index, false),
onFocus: (e: React.FocusEvent<HTMLDivElement>) => {
toggleTooltipOpen(index, true);
const passedProps: typeof nodeProps = {
...nodeProps,
onMouseEnter: (e) => {
setHoverOpen(true);
nodeProps.onMouseEnter?.(e);
},
onMouseLeave: (e) => {
setHoverOpen(false);
nodeProps.onMouseLeave?.(e);
},
onMouseDown: (e) => {
setFocusOpen(true);
setDragging(true);
nodeProps.onMouseDown?.(e);
},
onFocus: (e) => {
setFocusOpen(true);
restProps.onFocus?.(e);
nodeProps.onFocus?.(e);
},
onBlur: (e: React.FocusEvent<HTMLDivElement>) => {
toggleTooltipOpen(index, false);
onBlur: (e) => {
setFocusOpen(false);
restProps.onBlur?.(e);
nodeProps.onBlur?.(e);
},
};
return (
<SliderTooltip
{...tooltipProps}
prefixCls={getPrefixCls('tooltip', customizeTooltipPrefixCls ?? legacyTooltipPrefixCls)}
title={mergedTipFormatter ? mergedTipFormatter(info.value) : ''}
open={open}
placement={getTooltipPlacement(tooltipPlacement ?? legacyTooltipPlacement, vertical)}
key={index}
overlayClassName={`${prefixCls}-tooltip`}
getPopupContainer={
getTooltipPopupContainer || legacyGetTooltipPopupContainer || getPopupContainer
}
>
{React.cloneElement(node, passedProps)}
</SliderTooltip>
);
const cloneNode = React.cloneElement(node, passedProps);
// Wrap on handle with Tooltip when is single mode or multiple with all show tooltip
if (!useActiveTooltipHandle) {
return (
<SliderTooltip
{...tooltipProps}
prefixCls={getPrefixCls('tooltip', customizeTooltipPrefixCls ?? legacyTooltipPrefixCls)}
title={mergedTipFormatter ? mergedTipFormatter(info.value) : ''}
open={!!lockOpen || activeOpen}
placement={getTooltipPlacement(tooltipPlacement ?? legacyTooltipPlacement, vertical)}
key={index}
overlayClassName={`${prefixCls}-tooltip`}
getPopupContainer={
getTooltipPopupContainer || legacyGetTooltipPopupContainer || getPopupContainer
}
>
{cloneNode}
</SliderTooltip>
);
}
return cloneNode;
};
// ========================== Active Handle ===========================
const activeHandleRender: SliderProps['activeHandleRender'] = useActiveTooltipHandle
? (handle, info) => {
const cloneNode = React.cloneElement(handle, {
style: {
...handle.props.style,
visibility: 'hidden',
},
});
return (
<SliderTooltip
{...tooltipProps}
prefixCls={getPrefixCls('tooltip', customizeTooltipPrefixCls ?? legacyTooltipPrefixCls)}
title={mergedTipFormatter ? mergedTipFormatter(info.value) : ''}
open={activeOpen}
placement={getTooltipPlacement(tooltipPlacement ?? legacyTooltipPlacement, vertical)}
key="tooltip"
overlayClassName={`${prefixCls}-tooltip`}
getPopupContainer={
getTooltipPopupContainer || legacyGetTooltipPopupContainer || getPopupContainer
}
>
{cloneNode}
</SliderTooltip>
);
}
: undefined;
// ============================== Render ==============================
const mergedStyle: React.CSSProperties = { ...slider?.style, ...style };
return wrapCSSVar(
@ -273,6 +359,8 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
ref={ref}
prefixCls={prefixCls}
handleRender={handleRender}
activeHandleRender={activeHandleRender}
onChangeComplete={onInternalChangeComplete}
/>,
);
});

View File

@ -256,6 +256,12 @@ const genBaseStyle: GenerateStyle<SliderToken> = (token) => {
},
},
[`&-lock ${componentCls}-handle`]: {
[`&::before, &::after`]: {
transition: 'none',
},
},
[`${componentCls}-mark`]: {
position: 'absolute',
fontSize: token.fontSize,

View File

@ -0,0 +1,27 @@
import * as React from 'react';
import raf from 'rc-util/lib/raf';
export default function useRafLock(): [state: boolean, setState: (nextState: boolean) => void] {
const [state, setState] = React.useState(false);
const rafRef = React.useRef<number>();
const cleanup = () => {
raf.cancel(rafRef.current!);
};
const setDelayState = (nextState: boolean) => {
cleanup();
if (nextState) {
setState(nextState);
} else {
rafRef.current = raf(() => {
setState(nextState);
});
}
};
React.useEffect(() => cleanup, []);
return [state, setDelayState];
}

View File

@ -151,7 +151,7 @@
"rc-resize-observer": "^1.4.0",
"rc-segmented": "~2.3.0",
"rc-select": "~14.13.1",
"rc-slider": "~10.5.0",
"rc-slider": "~10.6.1",
"rc-steps": "~6.0.1",
"rc-switch": "~4.1.0",
"rc-table": "~7.45.4",