2
2
import * as React from 'react' ;
3
3
import classNames from 'classnames' ;
4
4
import useMobile from 'rc-util/lib/hooks/useMobile' ;
5
+ import raf from 'rc-util/lib/raf' ;
5
6
6
7
/**
7
8
* When click and hold on a button - the speed of auto changing the value.
@@ -32,13 +33,20 @@ export default function StepHandler({
32
33
} : StepHandlerProps ) {
33
34
// ======================== Step ========================
34
35
const stepTimeoutRef = React . useRef < any > ( ) ;
36
+ const frameIds = React . useRef < number [ ] > ( [ ] ) ;
35
37
36
38
const onStepRef = React . useRef < StepHandlerProps [ 'onStep' ] > ( ) ;
37
39
onStepRef . current = onStep ;
38
40
41
+ const onStopStep = ( ) => {
42
+ clearTimeout ( stepTimeoutRef . current ) ;
43
+ } ;
44
+
45
+
39
46
// We will interval update step when hold mouse down
40
47
const onStepMouseDown = ( e : React . MouseEvent , up : boolean ) => {
41
48
e . preventDefault ( ) ;
49
+ onStopStep ( ) ;
42
50
43
51
onStepRef . current ( up ) ;
44
52
@@ -53,11 +61,10 @@ export default function StepHandler({
53
61
stepTimeoutRef . current = setTimeout ( loopStep , STEP_DELAY ) ;
54
62
} ;
55
63
56
- const onStopStep = ( ) => {
57
- clearTimeout ( stepTimeoutRef . current ) ;
58
- } ;
59
-
60
- React . useEffect ( ( ) => onStopStep , [ ] ) ;
64
+ React . useEffect ( ( ) => ( ) => {
65
+ onStopStep ( ) ;
66
+ frameIds . current . forEach ( id => raf . cancel ( id ) ) ;
67
+ } , [ ] ) ;
61
68
62
69
// ======================= Render =======================
63
70
const isMobile = useMobile ( ) ;
@@ -74,11 +81,18 @@ export default function StepHandler({
74
81
[ `${ handlerClassName } -down-disabled` ] : downDisabled ,
75
82
} ) ;
76
83
84
+ // fix: https://github.com/ant-design/ant-design/issues/43088
85
+ // In Safari, When we fire onmousedown and onmouseup events in quick succession,
86
+ // there may be a problem that the onmouseup events are executed first,
87
+ // resulting in a disordered program execution.
88
+ // So, we need to use requestAnimationFrame to ensure that the onmouseup event is executed after the onmousedown event.
89
+ const safeOnStopStep = ( ) => frameIds . current . push ( raf ( onStopStep ) ) ;
90
+
77
91
const sharedHandlerProps = {
78
92
unselectable : 'on' as const ,
79
93
role : 'button' ,
80
- onMouseUp : onStopStep ,
81
- onMouseLeave : onStopStep ,
94
+ onMouseUp : safeOnStopStep ,
95
+ onMouseLeave : safeOnStopStep ,
82
96
} ;
83
97
84
98
return (
0 commit comments