@@ -25,17 +25,21 @@ class SwipeableListItem extends PureComponent {
25
25
this . contentLeft = null ;
26
26
this . contentRight = null ;
27
27
this . listElement = null ;
28
+ this . requestedAnimationFrame = null ;
28
29
this . wrapper = null ;
29
30
30
31
this . startTime = null ;
31
32
33
+ this . previousSwipeDistancePercent = 0 ;
34
+
32
35
this . resetState ( ) ;
33
36
}
34
37
35
38
resetState = ( ) => {
36
39
this . dragStartPoint = { x : - 1 , y : - 1 } ;
37
40
this . dragDirection = DragDirection . UNKNOWN ;
38
41
this . left = 0 ;
42
+ this . previousSwipeDistancePercent = 0 ;
39
43
} ;
40
44
41
45
get dragHorizontalDirectionThreshold ( ) {
@@ -58,6 +62,12 @@ class SwipeableListItem extends PureComponent {
58
62
}
59
63
60
64
componentWillUnmount ( ) {
65
+ if ( this . requestedAnimationFrame ) {
66
+ cancelAnimationFrame ( this . requestedAnimationFrame ) ;
67
+
68
+ this . requestedAnimationFrame = null ;
69
+ }
70
+
61
71
this . wrapper . removeEventListener ( 'mousedown' , this . handleDragStartMouse ) ;
62
72
63
73
this . wrapper . removeEventListener ( 'touchstart' , this . handleDragStartTouch ) ;
@@ -90,16 +100,16 @@ class SwipeableListItem extends PureComponent {
90
100
this . dragStartPoint = { x : clientX , y : clientY } ;
91
101
92
102
this . listElement . className = styles . content ;
93
- if ( this . contentLeft ) {
103
+ if ( this . contentLeft !== null ) {
94
104
this . contentLeft . className = styles . contentLeft ;
95
105
}
96
106
97
- if ( this . contentRight ) {
107
+ if ( this . contentRight !== null ) {
98
108
this . contentRight . className = styles . contentRight ;
99
109
}
100
110
101
111
this . startTime = Date . now ( ) ;
102
- requestAnimationFrame ( this . updatePosition ) ;
112
+ this . scheduleUpdatePosition ( ) ;
103
113
} ;
104
114
105
115
handleMouseMove = event => {
@@ -112,11 +122,8 @@ class SwipeableListItem extends PureComponent {
112
122
event . stopPropagation ( ) ;
113
123
event . preventDefault ( ) ;
114
124
115
- const delta = clientX - this . dragStartPoint . x ;
116
-
117
- if ( this . shouldMoveItem ( delta ) ) {
118
- this . left = delta ;
119
- }
125
+ this . left = clientX - this . dragStartPoint . x ;
126
+ this . scheduleUpdatePosition ( ) ;
120
127
}
121
128
}
122
129
} ;
@@ -135,11 +142,8 @@ class SwipeableListItem extends PureComponent {
135
142
event . stopPropagation ( ) ;
136
143
event . preventDefault ( ) ;
137
144
138
- const delta = clientX - this . dragStartPoint . x ;
139
-
140
- if ( this . shouldMoveItem ( delta ) ) {
141
- this . left = delta ;
142
- }
145
+ this . left = clientX - this . dragStartPoint . x ;
146
+ this . scheduleUpdatePosition ( ) ;
143
147
}
144
148
}
145
149
} ;
@@ -148,8 +152,10 @@ class SwipeableListItem extends PureComponent {
148
152
window . removeEventListener ( 'mouseup' , this . handleDragEndMouse ) ;
149
153
window . removeEventListener ( 'mousemove' , this . handleMouseMove ) ;
150
154
151
- this . wrapper . removeEventListener ( 'mouseup' , this . handleDragEndMouse ) ;
152
- this . wrapper . removeEventListener ( 'mousemove' , this . handleMouseMove ) ;
155
+ if ( this . wrapper ) {
156
+ this . wrapper . removeEventListener ( 'mouseup' , this . handleDragEndMouse ) ;
157
+ this . wrapper . removeEventListener ( 'mousemove' , this . handleMouseMove ) ;
158
+ }
153
159
154
160
this . handleDragEnd ( ) ;
155
161
} ;
@@ -169,39 +175,31 @@ class SwipeableListItem extends PureComponent {
169
175
} else if ( this . left > this . listElement . offsetWidth * threshold ) {
170
176
this . handleSwipedRight ( ) ;
171
177
}
178
+
179
+ if ( this . props . onSwipeEnd ) {
180
+ this . props . onSwipeEnd ( ) ;
181
+ }
172
182
}
173
183
174
184
this . resetState ( ) ;
175
- this . listElement . className = styles . contentReturn ;
176
- this . listElement . style . transform = `translateX(${ this . left } px)` ;
185
+
186
+ if ( this . listElement ) {
187
+ this . listElement . className = styles . contentReturn ;
188
+ this . listElement . style . transform = `translateX(${ this . left } px)` ;
189
+ }
177
190
178
191
// hide backgrounds
179
- if ( this . contentLeft ) {
192
+ if ( this . contentLeft !== null ) {
180
193
this . contentLeft . style . opacity = 0 ;
181
194
this . contentLeft . className = styles . contentLeftReturn ;
182
195
}
183
196
184
- if ( this . contentRight ) {
197
+ if ( this . contentRight !== null ) {
185
198
this . contentRight . style . opacity = 0 ;
186
199
this . contentRight . className = styles . contentRightReturn ;
187
200
}
188
201
} ;
189
202
190
- shouldMoveItem = delta => {
191
- const {
192
- swipeLeft : { content : contentLeft } = { } ,
193
- swipeRight : { content : contentRight } = { } ,
194
- blockSwipe
195
- } = this . props ;
196
- const swipingLeft = delta < 0 ;
197
- const swipingRight = delta > 0 ;
198
-
199
- return (
200
- ! blockSwipe &&
201
- ( ( swipingLeft && contentLeft ) || ( swipingRight && contentRight ) )
202
- ) ;
203
- } ;
204
-
205
203
dragStartedWithinItem = ( ) => {
206
204
const { x, y } = this . dragStartPoint ;
207
205
@@ -226,7 +224,10 @@ class SwipeableListItem extends PureComponent {
226
224
227
225
switch ( octant ) {
228
226
case 0 :
229
- if ( horizontalDistance > this . dragHorizontalDirectionThreshold ) {
227
+ if (
228
+ this . contentRight !== null &&
229
+ horizontalDistance > this . dragHorizontalDirectionThreshold
230
+ ) {
230
231
this . dragDirection = DragDirection . RIGHT ;
231
232
}
232
233
break ;
@@ -238,7 +239,10 @@ class SwipeableListItem extends PureComponent {
238
239
}
239
240
break ;
240
241
case 4 :
241
- if ( horizontalDistance > this . dragHorizontalDirectionThreshold ) {
242
+ if (
243
+ this . contentLeft !== null &&
244
+ horizontalDistance > this . dragHorizontalDirectionThreshold
245
+ ) {
242
246
this . dragDirection = DragDirection . LEFT ;
243
247
}
244
248
break ;
@@ -250,21 +254,35 @@ class SwipeableListItem extends PureComponent {
250
254
}
251
255
break ;
252
256
}
257
+
258
+ if ( this . props . onSwipeStart && this . isSwiping ( ) ) {
259
+ this . props . onSwipeStart ( ) ;
260
+ }
253
261
}
254
262
} ;
255
263
256
- isSwiping = ( ) =>
257
- this . dragStartedWithinItem ( ) &&
258
- ( this . dragDirection === DragDirection . LEFT ||
259
- this . dragDirection === DragDirection . RIGHT ) ;
260
-
261
- updatePosition = ( ) => {
264
+ isSwiping = ( ) => {
262
265
const { blockSwipe } = this . props ;
266
+ const horizontalDrag =
267
+ this . dragDirection === DragDirection . LEFT ||
268
+ this . dragDirection === DragDirection . RIGHT ;
269
+
270
+ return ! blockSwipe && this . dragStartedWithinItem ( ) && horizontalDrag ;
271
+ } ;
263
272
264
- if ( this . dragStartedWithinItem ( ) && ! blockSwipe ) {
265
- requestAnimationFrame ( this . updatePosition ) ;
273
+ scheduleUpdatePosition = ( ) => {
274
+ if ( this . requestedAnimationFrame ) {
275
+ return ;
266
276
}
267
277
278
+ this . requestedAnimationFrame = requestAnimationFrame ( ( ) => {
279
+ this . requestedAnimationFrame = null ;
280
+
281
+ this . updatePosition ( ) ;
282
+ } ) ;
283
+ } ;
284
+
285
+ updatePosition = ( ) => {
268
286
const now = Date . now ( ) ;
269
287
const elapsed = now - this . startTime ;
270
288
@@ -279,6 +297,26 @@ class SwipeableListItem extends PureComponent {
279
297
280
298
const opacity = ( Math . abs ( this . left ) / 100 ) . toFixed ( 2 ) ;
281
299
300
+ if ( this . props . onSwipeProgress && this . listElement !== null ) {
301
+ const listElementWidth = this . listElement . offsetWidth ;
302
+ let swipeDistancePercent = this . previousSwipeDistancePercent ;
303
+
304
+ if ( listElementWidth !== 0 ) {
305
+ const swipeDistance = Math . max (
306
+ 0 ,
307
+ listElementWidth - Math . abs ( this . left )
308
+ ) ;
309
+
310
+ swipeDistancePercent =
311
+ 100 - Math . round ( ( 100 * swipeDistance ) / listElementWidth ) ;
312
+ }
313
+
314
+ if ( this . previousSwipeDistancePercent !== swipeDistancePercent ) {
315
+ this . props . onSwipeProgress ( swipeDistancePercent ) ;
316
+ this . previousSwipeDistancePercent = swipeDistancePercent ;
317
+ }
318
+ }
319
+
282
320
if ( opacity < 1 && opacity . toString ( ) !== contentToShow . style . opacity ) {
283
321
contentToShow . style . opacity = opacity . toString ( ) ;
284
322
@@ -361,7 +399,11 @@ SwipeableListItem.propTypes = {
361
399
swipeRight : SwipeActionPropType ,
362
400
scrollStartThreshold : PropTypes . number ,
363
401
swipeStartThreshold : PropTypes . number ,
364
- threshold : PropTypes . number
402
+ threshold : PropTypes . number ,
403
+
404
+ onSwipeEnd : PropTypes . func ,
405
+ onSwipeProgress : PropTypes . func ,
406
+ onSwipeStart : PropTypes . func
365
407
} ;
366
408
367
409
export default SwipeableListItem ;
0 commit comments