@@ -39,36 +39,25 @@ export interface MoveProps {
39
39
onMoveEnd ?: ( e : MoveEndEvent ) => void
40
40
}
41
41
42
- // const currentTargets: Set<HTMLElement> = new Set();
43
- let currentTarget : HTMLElement | null = null ;
44
-
45
42
export function useMove ( props : MoveProps ) : HTMLAttributes < HTMLElement > {
46
43
let { onMoveStart, onMove, onMoveEnd} = props ;
47
44
48
- let state = useRef ( { movedAfterDown : false , previousPosition : null } ) ;
45
+ let state = useRef < {
46
+ didMove : boolean ,
47
+ lastPosition : { pageX : number , pageY : number } | null ,
48
+ id : number | null
49
+ } > ( { didMove : false , lastPosition : null , id : null } ) ;
49
50
50
51
let moveProps = useMemo ( ( ) => {
51
52
let moveProps : HTMLAttributes < HTMLElement > = { } ;
52
53
53
- let start = ( target ?: any ) => {
54
- // Only move innermost element that is using useMove, not potential parents.
55
- if ( target ) {
56
- if ( currentTarget ) {
57
- return false ;
58
- }
59
- // if ([...currentTargets].some(e => e.contains(target))) {
60
- // return false;
61
- // }
62
- // currentTargets.add(target);
63
- currentTarget = target ;
64
- }
54
+ let start = ( ) => {
65
55
disableTextSelection ( ) ;
66
- state . current . movedAfterDown = false ;
67
- return true ;
56
+ state . current . didMove = false ;
68
57
} ;
69
58
let move = ( pointerType : BaseMoveEvent [ 'pointerType' ] , deltaX : number , deltaY : number ) => {
70
- if ( ! state . current . movedAfterDown ) {
71
- state . current . movedAfterDown = true ;
59
+ if ( ! state . current . didMove ) {
60
+ state . current . didMove = true ;
72
61
onMoveStart ?.( {
73
62
type : 'movestart' ,
74
63
pointerType
@@ -81,18 +70,9 @@ export function useMove(props: MoveProps): HTMLAttributes<HTMLElement> {
81
70
deltaY : deltaY
82
71
} ) ;
83
72
} ;
84
- let end = ( pointerType : BaseMoveEvent [ 'pointerType' ] /* , target?: any */ ) => {
85
- currentTarget = null ;
86
- // if (target) {
87
- // for (let e of currentTargets) {
88
- // // The cursor might be let go on some parent element.
89
- // if (target.contains(e) || e.contains(target)) {
90
- // currentTargets.delete(e);
91
- // }
92
- // }
93
- // }
73
+ let end = ( pointerType : BaseMoveEvent [ 'pointerType' ] ) => {
94
74
restoreTextSelection ( ) ;
95
- if ( state . current . movedAfterDown ) {
75
+ if ( state . current . didMove ) {
96
76
onMoveEnd ?.( {
97
77
type : 'moveend' ,
98
78
pointerType
@@ -102,73 +82,95 @@ export function useMove(props: MoveProps): HTMLAttributes<HTMLElement> {
102
82
103
83
if ( typeof PointerEvent === 'undefined' ) {
104
84
let onMouseMove = ( e : MouseEvent ) => {
105
- move ( 'mouse' , e . pageX - state . current . previousPosition . pageX , e . pageY - state . current . previousPosition . pageY ) ;
106
- state . current . previousPosition = { pageX : e . pageX , pageY : e . pageY } ;
85
+ if ( e . button === 0 ) {
86
+ move ( 'mouse' , e . pageX - state . current . lastPosition . pageX , e . pageY - state . current . lastPosition . pageY ) ;
87
+ state . current . lastPosition = { pageX : e . pageX , pageY : e . pageY } ;
88
+ }
107
89
} ;
108
- let onMouseUp = ( /* e: MouseEvent */ ) => {
109
- end ( 'mouse' /* , e.target */ ) ;
110
- window . removeEventListener ( 'mousemove' , onMouseMove , false ) ;
111
- window . removeEventListener ( 'mouseup' , onMouseUp , false ) ;
90
+ let onMouseUp = ( e : MouseEvent ) => {
91
+ if ( e . button === 0 ) {
92
+ end ( 'mouse' ) ;
93
+ window . removeEventListener ( 'mousemove' , onMouseMove , false ) ;
94
+ window . removeEventListener ( 'mouseup' , onMouseUp , false ) ;
95
+ }
112
96
} ;
113
97
moveProps . onMouseDown = ( e : React . MouseEvent ) => {
114
- if ( e . button === 0 && start ( e . target ) ) {
98
+ if ( e . button === 0 ) {
99
+ start ( ) ;
115
100
e . stopPropagation ( ) ;
116
101
e . preventDefault ( ) ;
117
- state . current . previousPosition = { pageX : e . pageX , pageY : e . pageY } ;
102
+ state . current . lastPosition = { pageX : e . pageX , pageY : e . pageY } ;
118
103
window . addEventListener ( 'mousemove' , onMouseMove , false ) ;
119
104
window . addEventListener ( 'mouseup' , onMouseUp , false ) ;
120
105
}
121
106
} ;
122
107
123
108
let onTouchMove = ( e : TouchEvent ) => {
124
- // TODO which touch?
125
- let { pageX, pageY} = e . targetTouches [ 0 ] ;
126
- move ( 'touch' , pageX - state . current . previousPosition . pageX , pageY - state . current . previousPosition . pageY ) ;
127
- state . current . previousPosition = { pageX, pageY} ;
109
+ // @ts -ignore
110
+ let touch = [ ...e . changedTouches ] . findIndex ( ( { identifier} ) => identifier === state . current . id ) ;
111
+ if ( touch >= 0 ) {
112
+ let { pageX, pageY} = e . changedTouches [ touch ] ;
113
+ move ( 'touch' , pageX - state . current . lastPosition . pageX , pageY - state . current . lastPosition . pageY ) ;
114
+ state . current . lastPosition = { pageX, pageY} ;
115
+ }
128
116
} ;
129
- let onTouchEnd = ( /* e: TouchEvent */ ) => {
130
- end ( 'touch' /* , e.target */ ) ;
131
- window . removeEventListener ( 'touchmove' , onTouchMove ) ;
132
- window . removeEventListener ( 'touchend' , onTouchEnd ) ;
133
- window . removeEventListener ( 'touchcancel' , onTouchEnd ) ;
117
+ let onTouchEnd = ( e : TouchEvent ) => {
118
+ // @ts -ignore
119
+ let touch = [ ...e . changedTouches ] . findIndex ( ( { identifier} ) => identifier === state . current . id ) ;
120
+ if ( touch >= 0 ) {
121
+ end ( 'touch' ) ;
122
+ window . removeEventListener ( 'touchmove' , onTouchMove ) ;
123
+ window . removeEventListener ( 'touchend' , onTouchEnd ) ;
124
+ window . removeEventListener ( 'touchcancel' , onTouchEnd ) ;
125
+ }
134
126
} ;
135
127
moveProps . onTouchStart = ( e : React . TouchEvent ) => {
136
- if ( start ( e . target ) ) {
137
- e . stopPropagation ( ) ;
138
- e . preventDefault ( ) ;
139
- let { pageX, pageY} = e . targetTouches [ 0 ] ;
140
- state . current . previousPosition = { pageX, pageY} ;
141
- window . addEventListener ( 'touchmove' , onTouchMove , false ) ;
142
- window . addEventListener ( 'touchend' , onTouchEnd , false ) ;
143
- window . addEventListener ( 'touchcancel' , onTouchEnd , false ) ;
128
+ if ( e . targetTouches . length === 0 ) {
129
+ return ;
144
130
}
131
+
132
+ let { pageX, pageY, identifier} = e . targetTouches [ 0 ] ;
133
+ start ( ) ;
134
+ e . stopPropagation ( ) ;
135
+ e . preventDefault ( ) ;
136
+ state . current . lastPosition = { pageX, pageY} ;
137
+ state . current . id = identifier ;
138
+ window . addEventListener ( 'touchmove' , onTouchMove , false ) ;
139
+ window . addEventListener ( 'touchend' , onTouchEnd , false ) ;
140
+ window . addEventListener ( 'touchcancel' , onTouchEnd , false ) ;
145
141
} ;
146
142
} else {
147
143
let onPointerMove = ( e : PointerEvent ) => {
148
- // @ts -ignore
149
- let pointerType : BaseMoveEvent [ 'pointerType' ] = e . pointerType || 'mouse' ;
150
-
151
- // Problems with PointerEvent#movementX/movementY:
152
- // 1. it is always 0 on macOS Safari.
153
- // 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS
154
- move ( pointerType , e . pageX - state . current . previousPosition . pageX , e . pageY - state . current . previousPosition . pageY ) ;
155
- state . current . previousPosition = { pageX : e . pageX , pageY : e . pageY } ;
144
+ if ( e . pointerId === state . current . id ) {
145
+ // @ts -ignore
146
+ let pointerType : BaseMoveEvent [ 'pointerType' ] = e . pointerType || 'mouse' ;
147
+
148
+ // Problems with PointerEvent#movementX/movementY:
149
+ // 1. it is always 0 on macOS Safari.
150
+ // 2. On Chrome Android, it's scaled by devicePixelRatio, but not on Chrome macOS
151
+ move ( pointerType , e . pageX - state . current . lastPosition . pageX , e . pageY - state . current . lastPosition . pageY ) ;
152
+ state . current . lastPosition = { pageX : e . pageX , pageY : e . pageY } ;
153
+ }
156
154
} ;
157
155
158
156
let onPointerUp = ( e : PointerEvent ) => {
159
- // @ts -ignore
160
- let pointerType : BaseMoveEvent [ 'pointerType' ] = e . pointerType || 'mouse' ;
161
- end ( pointerType /* , e.target */ ) ;
162
- window . removeEventListener ( 'pointermove' , onPointerMove , false ) ;
163
- window . removeEventListener ( 'pointerup' , onPointerUp , false ) ;
164
- window . removeEventListener ( 'pointercancel' , onPointerUp , false ) ;
157
+ if ( e . pointerId === state . current . id ) {
158
+ // @ts -ignore
159
+ let pointerType : BaseMoveEvent [ 'pointerType' ] = e . pointerType || 'mouse' ;
160
+ end ( pointerType /* , e.target */ ) ;
161
+ window . removeEventListener ( 'pointermove' , onPointerMove , false ) ;
162
+ window . removeEventListener ( 'pointerup' , onPointerUp , false ) ;
163
+ window . removeEventListener ( 'pointercancel' , onPointerUp , false ) ;
164
+ }
165
165
} ;
166
166
167
167
moveProps . onPointerDown = ( e : React . PointerEvent ) => {
168
- if ( e . button === 0 && start ( e . target ) ) {
168
+ if ( e . button === 0 ) {
169
+ start ( ) ;
169
170
e . stopPropagation ( ) ;
170
171
e . preventDefault ( ) ;
171
- state . current . previousPosition = { pageX : e . pageX , pageY : e . pageY } ;
172
+ state . current . lastPosition = { pageX : e . pageX , pageY : e . pageY } ;
173
+ state . current . id = e . pointerId ;
172
174
window . addEventListener ( 'pointermove' , onPointerMove , false ) ;
173
175
window . addEventListener ( 'pointerup' , onPointerUp , false ) ;
174
176
window . addEventListener ( 'pointercancel' , onPointerUp , false ) ;
0 commit comments