@@ -351,6 +351,7 @@ export default class Card extends React.Component<Props> {
351351 private offset = new Value ( 0 ) ;
352352 private velocityUntraversed = new Value ( 0 ) ;
353353 private velocity = new Value ( 0 ) ;
354+ private didMovementHappen = new Value ( 0 ) ;
354355
355356 private gestureState = new Value ( 0 ) ;
356357
@@ -404,98 +405,126 @@ export default class Card extends React.Component<Props> {
404405 private runTransition = ( isVisible : Binary | Animated . Node < number > ) => {
405406 const { open : openingSpec , close : closingSpec } = this . props . transitionSpec ;
406407
407- return cond ( eq ( this . props . current , isVisible ) , NOOP_NODE , [
408- cond ( clockRunning ( this . clock ) , NOOP_NODE , [
409- // Animation wasn't running before
410- // Set the initial values and start the clock
411- set ( this . toValue , isVisible ) ,
412- // The velocity value is ideal for translating the whole screen
413- // But since we have 0-1 scale, we need to adjust the velocity
414- set (
415- this . transitionVelocity ,
416- multiply (
417- cond (
418- this . distance ,
419- divide ( this . velocity , this . distance ) ,
420- FALSE_NODE
421- ) ,
422- - 1
423- )
424- ) ,
425- set ( this . frameTime , FALSE_NODE ) ,
426- set ( this . transitionState . time , FALSE_NODE ) ,
427- set ( this . transitionState . finished , FALSE_NODE ) ,
428- set ( this . isVisible , isVisible ) ,
429- startClock ( this . clock ) ,
430- call ( [ this . isVisible ] , ( [ value ] : ReadonlyArray < Binary > ) => {
431- this . handleStartInteraction ( ) ;
432-
433- const { onTransitionStart } = this . props ;
434- this . noAnimationStartedSoFar = false ;
435- this . isRunningAnimation = true ;
436- onTransitionStart && onTransitionStart ( { closing : ! value } ) ;
437- } ) ,
438- ] ) ,
408+ return [
439409 cond (
440- eq ( isVisible , TRUE_NODE ) ,
441- openingSpec . animation === 'spring'
442- ? memoizedSpring (
443- this . clock ,
444- { ...this . transitionState , velocity : this . transitionVelocity } ,
445- // @ts -ignore
446- {
447- ...( this . openingSpecConfig as AnimatedSpringConfig ) ,
448- toValue : this . toValue ,
449- }
450- )
451- : timing (
452- this . clock ,
453- { ...this . transitionState , frameTime : this . frameTime } ,
454- {
455- ...( this . openingSpecConfig as AnimatedTimingConfig ) ,
456- toValue : this . toValue ,
457- }
410+ eq ( this . props . current , isVisible ) ,
411+ call (
412+ [ this . didMovementHappen , this . isVisible ] ,
413+ ( [ didMovementHappen ] : ReadonlyArray < Binary > ) => {
414+ if ( didMovementHappen ) {
415+ // if we go back to the same position,
416+ // let's pretend that whole animation happen
417+ // for making the logic consistent
418+ // It's especially vital for having inputs properly focused.
419+ this . handleStartInteraction ( ) ;
420+ const { onTransitionStart } = this . props ;
421+ onTransitionStart && onTransitionStart ( { closing : true } ) ;
422+ this . handleTransitionEnd ( ) ;
423+ this . props . onOpen ( true ) ;
424+ }
425+ }
426+ ) ,
427+ [
428+ cond ( clockRunning ( this . clock ) , NOOP_NODE , [
429+ // Animation wasn't running before
430+ // Set the initial values and start the clock
431+ set ( this . toValue , isVisible ) ,
432+ // The velocity value is ideal for translating the whole screen
433+ // But since we have 0-1 scale, we need to adjust the velocity
434+ set (
435+ this . transitionVelocity ,
436+ multiply (
437+ cond (
438+ this . distance ,
439+ divide ( this . velocity , this . distance ) ,
440+ FALSE_NODE
441+ ) ,
442+ - 1
443+ )
458444 ) ,
459- closingSpec . animation === 'spring'
460- ? memoizedSpring (
461- this . clock ,
462- { ...this . transitionState , velocity : this . transitionVelocity } ,
463- // @ts -ignore
464- {
465- ...( this . closingSpecConfig as AnimatedSpringConfig ) ,
466- toValue : this . toValue ,
467- }
468- )
469- : timing (
470- this . clock ,
471- { ...this . transitionState , frameTime : this . frameTime } ,
472- {
473- ...( this . closingSpecConfig as AnimatedTimingConfig ) ,
474- toValue : this . toValue ,
445+ set ( this . frameTime , FALSE_NODE ) ,
446+ set ( this . transitionState . time , FALSE_NODE ) ,
447+ set ( this . transitionState . finished , FALSE_NODE ) ,
448+ set ( this . isVisible , isVisible ) ,
449+ startClock ( this . clock ) ,
450+ call ( [ this . isVisible ] , ( [ value ] : ReadonlyArray < Binary > ) => {
451+ this . handleStartInteraction ( ) ;
452+
453+ const { onTransitionStart } = this . props ;
454+ this . noAnimationStartedSoFar = false ;
455+ this . isRunningAnimation = true ;
456+ onTransitionStart && onTransitionStart ( { closing : ! value } ) ;
457+ } ) ,
458+ ] ) ,
459+ cond (
460+ eq ( isVisible , TRUE_NODE ) ,
461+ openingSpec . animation === 'spring'
462+ ? memoizedSpring (
463+ this . clock ,
464+ {
465+ ...this . transitionState ,
466+ velocity : this . transitionVelocity ,
467+ } ,
468+ // @ts -ignore
469+ {
470+ ...( this . openingSpecConfig as AnimatedSpringConfig ) ,
471+ toValue : this . toValue ,
472+ }
473+ )
474+ : timing (
475+ this . clock ,
476+ { ...this . transitionState , frameTime : this . frameTime } ,
477+ {
478+ ...( this . openingSpecConfig as AnimatedTimingConfig ) ,
479+ toValue : this . toValue ,
480+ }
481+ ) ,
482+ closingSpec . animation === 'spring'
483+ ? memoizedSpring (
484+ this . clock ,
485+ {
486+ ...this . transitionState ,
487+ velocity : this . transitionVelocity ,
488+ } ,
489+ // @ts -ignore
490+ {
491+ ...( this . closingSpecConfig as AnimatedSpringConfig ) ,
492+ toValue : this . toValue ,
493+ }
494+ )
495+ : timing (
496+ this . clock ,
497+ { ...this . transitionState , frameTime : this . frameTime } ,
498+ {
499+ ...( this . closingSpecConfig as AnimatedTimingConfig ) ,
500+ toValue : this . toValue ,
501+ }
502+ )
503+ ) ,
504+ cond ( this . transitionState . finished , [
505+ // Reset values
506+ set ( this . isSwipeGesture , FALSE_NODE ) ,
507+ set ( this . gesture , FALSE_NODE ) ,
508+ set ( this . velocity , FALSE_NODE ) ,
509+ // When the animation finishes, stop the clock
510+ stopClock ( this . clock ) ,
511+ call ( [ this . isVisible ] , ( [ value ] : ReadonlyArray < Binary > ) => {
512+ const isOpen = Boolean ( value ) ;
513+ const { onOpen, onClose } = this . props ;
514+
515+ this . handleTransitionEnd ( ) ;
516+
517+ if ( isOpen ) {
518+ onOpen ( true ) ;
519+ } else {
520+ onClose ( true ) ;
475521 }
476- )
522+ } ) ,
523+ ] ) ,
524+ ]
477525 ) ,
478- cond ( this . transitionState . finished , [
479- // Reset values
480- set ( this . isSwipeGesture , FALSE_NODE ) ,
481- set ( this . gesture , FALSE_NODE ) ,
482- set ( this . velocity , FALSE_NODE ) ,
483- // When the animation finishes, stop the clock
484- stopClock ( this . clock ) ,
485- call ( [ this . isVisible ] , ( [ value ] : ReadonlyArray < Binary > ) => {
486- const isOpen = Boolean ( value ) ;
487- const { onOpen, onClose } = this . props ;
488-
489- this . handleTransitionEnd ( ) ;
490-
491- if ( isOpen ) {
492- onOpen ( true ) ;
493- } else {
494- onClose ( true ) ;
495- }
496- } ) ,
497- ] ) ,
498- ] ) ;
526+ set ( this . didMovementHappen , 0 ) ,
527+ ] ;
499528 } ;
500529
501530 private extrapolatedPosition = add (
@@ -576,6 +605,7 @@ export default class Card extends React.Component<Props> {
576605 }
577606 )
578607 ) ,
608+ onChange ( this . gestureUntraversed , set ( this . didMovementHappen , 1 ) ) ,
579609 cond (
580610 eq ( this . gestureState , GestureState . ACTIVE ) ,
581611 [
0 commit comments