@@ -25,17 +25,21 @@ class SwipeableListItem extends PureComponent {
2525 this . contentLeft = null ;
2626 this . contentRight = null ;
2727 this . listElement = null ;
28+ this . requestedAnimationFrame = null ;
2829 this . wrapper = null ;
2930
3031 this . startTime = null ;
3132
33+ this . previousSwipeDistancePercent = 0 ;
34+
3235 this . resetState ( ) ;
3336 }
3437
3538 resetState = ( ) => {
3639 this . dragStartPoint = { x : - 1 , y : - 1 } ;
3740 this . dragDirection = DragDirection . UNKNOWN ;
3841 this . left = 0 ;
42+ this . previousSwipeDistancePercent = 0 ;
3943 } ;
4044
4145 get dragHorizontalDirectionThreshold ( ) {
@@ -58,6 +62,12 @@ class SwipeableListItem extends PureComponent {
5862 }
5963
6064 componentWillUnmount ( ) {
65+ if ( this . requestedAnimationFrame ) {
66+ cancelAnimationFrame ( this . requestedAnimationFrame ) ;
67+
68+ this . requestedAnimationFrame = null ;
69+ }
70+
6171 this . wrapper . removeEventListener ( 'mousedown' , this . handleDragStartMouse ) ;
6272
6373 this . wrapper . removeEventListener ( 'touchstart' , this . handleDragStartTouch ) ;
@@ -90,16 +100,16 @@ class SwipeableListItem extends PureComponent {
90100 this . dragStartPoint = { x : clientX , y : clientY } ;
91101
92102 this . listElement . className = styles . content ;
93- if ( this . contentLeft ) {
103+ if ( this . contentLeft !== null ) {
94104 this . contentLeft . className = styles . contentLeft ;
95105 }
96106
97- if ( this . contentRight ) {
107+ if ( this . contentRight !== null ) {
98108 this . contentRight . className = styles . contentRight ;
99109 }
100110
101111 this . startTime = Date . now ( ) ;
102- requestAnimationFrame ( this . updatePosition ) ;
112+ this . scheduleUpdatePosition ( ) ;
103113 } ;
104114
105115 handleMouseMove = event => {
@@ -112,11 +122,8 @@ class SwipeableListItem extends PureComponent {
112122 event . stopPropagation ( ) ;
113123 event . preventDefault ( ) ;
114124
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 ( ) ;
120127 }
121128 }
122129 } ;
@@ -135,11 +142,8 @@ class SwipeableListItem extends PureComponent {
135142 event . stopPropagation ( ) ;
136143 event . preventDefault ( ) ;
137144
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 ( ) ;
143147 }
144148 }
145149 } ;
@@ -148,8 +152,10 @@ class SwipeableListItem extends PureComponent {
148152 window . removeEventListener ( 'mouseup' , this . handleDragEndMouse ) ;
149153 window . removeEventListener ( 'mousemove' , this . handleMouseMove ) ;
150154
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+ }
153159
154160 this . handleDragEnd ( ) ;
155161 } ;
@@ -169,39 +175,31 @@ class SwipeableListItem extends PureComponent {
169175 } else if ( this . left > this . listElement . offsetWidth * threshold ) {
170176 this . handleSwipedRight ( ) ;
171177 }
178+
179+ if ( this . props . onSwipeEnd ) {
180+ this . props . onSwipeEnd ( ) ;
181+ }
172182 }
173183
174184 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+ }
177190
178191 // hide backgrounds
179- if ( this . contentLeft ) {
192+ if ( this . contentLeft !== null ) {
180193 this . contentLeft . style . opacity = 0 ;
181194 this . contentLeft . className = styles . contentLeftReturn ;
182195 }
183196
184- if ( this . contentRight ) {
197+ if ( this . contentRight !== null ) {
185198 this . contentRight . style . opacity = 0 ;
186199 this . contentRight . className = styles . contentRightReturn ;
187200 }
188201 } ;
189202
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-
205203 dragStartedWithinItem = ( ) => {
206204 const { x, y } = this . dragStartPoint ;
207205
@@ -226,7 +224,10 @@ class SwipeableListItem extends PureComponent {
226224
227225 switch ( octant ) {
228226 case 0 :
229- if ( horizontalDistance > this . dragHorizontalDirectionThreshold ) {
227+ if (
228+ this . contentRight !== null &&
229+ horizontalDistance > this . dragHorizontalDirectionThreshold
230+ ) {
230231 this . dragDirection = DragDirection . RIGHT ;
231232 }
232233 break ;
@@ -238,7 +239,10 @@ class SwipeableListItem extends PureComponent {
238239 }
239240 break ;
240241 case 4 :
241- if ( horizontalDistance > this . dragHorizontalDirectionThreshold ) {
242+ if (
243+ this . contentLeft !== null &&
244+ horizontalDistance > this . dragHorizontalDirectionThreshold
245+ ) {
242246 this . dragDirection = DragDirection . LEFT ;
243247 }
244248 break ;
@@ -250,21 +254,35 @@ class SwipeableListItem extends PureComponent {
250254 }
251255 break ;
252256 }
257+
258+ if ( this . props . onSwipeStart && this . isSwiping ( ) ) {
259+ this . props . onSwipeStart ( ) ;
260+ }
253261 }
254262 } ;
255263
256- isSwiping = ( ) =>
257- this . dragStartedWithinItem ( ) &&
258- ( this . dragDirection === DragDirection . LEFT ||
259- this . dragDirection === DragDirection . RIGHT ) ;
260-
261- updatePosition = ( ) => {
264+ isSwiping = ( ) => {
262265 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+ } ;
263272
264- if ( this . dragStartedWithinItem ( ) && ! blockSwipe ) {
265- requestAnimationFrame ( this . updatePosition ) ;
273+ scheduleUpdatePosition = ( ) => {
274+ if ( this . requestedAnimationFrame ) {
275+ return ;
266276 }
267277
278+ this . requestedAnimationFrame = requestAnimationFrame ( ( ) => {
279+ this . requestedAnimationFrame = null ;
280+
281+ this . updatePosition ( ) ;
282+ } ) ;
283+ } ;
284+
285+ updatePosition = ( ) => {
268286 const now = Date . now ( ) ;
269287 const elapsed = now - this . startTime ;
270288
@@ -279,6 +297,26 @@ class SwipeableListItem extends PureComponent {
279297
280298 const opacity = ( Math . abs ( this . left ) / 100 ) . toFixed ( 2 ) ;
281299
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+
282320 if ( opacity < 1 && opacity . toString ( ) !== contentToShow . style . opacity ) {
283321 contentToShow . style . opacity = opacity . toString ( ) ;
284322
@@ -361,7 +399,11 @@ SwipeableListItem.propTypes = {
361399 swipeRight : SwipeActionPropType ,
362400 scrollStartThreshold : PropTypes . number ,
363401 swipeStartThreshold : PropTypes . number ,
364- threshold : PropTypes . number
402+ threshold : PropTypes . number ,
403+
404+ onSwipeEnd : PropTypes . func ,
405+ onSwipeProgress : PropTypes . func ,
406+ onSwipeStart : PropTypes . func
365407} ;
366408
367409export default SwipeableListItem ;
0 commit comments