Skip to content

Commit

Permalink
Replace RNGH with RN PanResponder to fix Android modals
Browse files Browse the repository at this point in the history
Even though work has been done, it would appear that RNGH doesn’t work
on Android within modals.

- https://git.io/JTkgM
- https://git.io/JTkgS
- https://git.io/JTkg9
- https://bit.ly/3nHbpVl
  • Loading branch information
shadow351 committed Oct 11, 2020
1 parent 2c3e212 commit 49c6cb4
Showing 1 changed file with 102 additions and 131 deletions.
233 changes: 102 additions & 131 deletions packages/components/src/focal-point-picker/index.native.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
/**
* External dependencies
*/
import { Animated, View } from 'react-native';
import {
PanGestureHandler,
TapGestureHandler,
State,
} from 'react-native-gesture-handler';
import { Animated, PanResponder, View } from 'react-native';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Image, RangeControl } from '@wordpress/components';
import { Path, SVG } from '@wordpress/primitives';
import { useRef, useState } from '@wordpress/element';
import { useRef, useState, useMemo } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -29,7 +24,41 @@ export default function FocalPointPicker( props ) {

const [ containerSize, setContainerSize ] = useState( null );
const [ sliderKey, setSliderKey ] = useState( 0 );
const panRef = useRef();

const pan = useRef( new Animated.ValueXY() ).current;
if ( containerSize ) {
pan.setValue( {
x: focalPoint.x * containerSize?.width,
y: focalPoint.y * containerSize?.height,
} );
}
const panResponder = useMemo(
() =>
PanResponder.create( {
// Ask to be the responder:
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,

onPanResponderGrant: ( event ) => {
extrapolatePositionFromGesture( event );
},
onPanResponderMove: ( event ) => {
shouldEnableBottomSheetScroll( false );
extrapolatePositionFromGesture( event );
},
onPanResponderTerminationRequest: () => true,
onPanResponderRelease: () => {
shouldEnableBottomSheetScroll( true );
// Slider (child of RangeCell) is uncontrolled, so we must increment a
// key to re-mount and sync the pan gesture values to the sliders
// https://git.io/JTe4A
setSliderKey( ( prevState ) => prevState + 1 );
},
} ),
[ containerSize ]
);

function setPosition( { x, y } ) {
onChange( ( prevState ) => ( {
Expand All @@ -39,33 +68,8 @@ export default function FocalPointPicker( props ) {
} ) );
}

const _touchX = new Animated.Value(
focalPoint.x * containerSize?.width || 1
);
const _touchY = new Animated.Value(
focalPoint.y * containerSize?.height || 1
);

function onHandlerStateChange( { nativeEvent } ) {
switch ( nativeEvent.state ) {
case State.BEGAN:
shouldEnableBottomSheetScroll( false );
break;
case State.ACTIVE:
shouldEnableBottomSheetScroll( false );
break;
default:
shouldEnableBottomSheetScroll( true );
// Slider (child of RangeCell) is uncontrolled, so we must increment a
// key to re-mount and sync the pan gesture values to the sliders
// https://git.io/JTe4A
setSliderKey( ( prevState ) => prevState + 1 );
break;
}
}

function extrapolatePositionFromGesture( event ) {
const { x, y } = event.nativeEvent;
const { locationX: x, locationY: y } = event.nativeEvent;
setPosition( {
x: x / containerSize?.width,
y: y / containerSize?.height,
Expand All @@ -75,108 +79,75 @@ export default function FocalPointPicker( props ) {
return (
<View style={ styles.container }>
<View style={ [ styles.media ] }>
<TapGestureHandler
onHandlerStateChange={ ( event ) => {
onHandlerStateChange( event );
extrapolatePositionFromGesture( event );
<View
{ ...panResponder.panHandlers }
onLayout={ ( event ) => {
const { height, width } = event.nativeEvent.layout;

if (
width !== 0 &&
height !== 0 &&
( containerSize?.width !== width ||
containerSize?.height !== height )
) {
setContainerSize( { width, height } );
}
} }
waitFor={ panRef }
style={ styles.imageContainer }
>
<PanGestureHandler
minDist={ 1 }
onHandlerStateChange={ onHandlerStateChange }
onGestureEvent={ Animated.event(
[ { nativeEvent: { x: _touchX, y: _touchY } } ],
<Image height="100%" url={ url } />
<Animated.View
pointerEvents="none"
style={ [
styles.focalPointWrapper,
{
useNativeDriver: false,
listener: extrapolatePositionFromGesture,
}
) }
ref={ panRef }
>
<Animated.View
onLayout={ ( event ) => {
const {
height,
width,
} = event.nativeEvent.layout;

if (
width !== 0 &&
height !== 0 &&
( containerSize?.width !== width ||
containerSize?.height !== height )
) {
setContainerSize( { width, height } );
}
} }
style={ styles.imageContainer }
>
<Image height="100%" url={ url } />
<Animated.View
pointerEvents="none"
style={ [
styles.focalPointWrapper,
transform: [
{
transform: [
{
translateX: _touchX.interpolate(
{
inputRange: [
0,
containerSize?.width ||
0,
],
outputRange: [
0,
containerSize?.width ||
0,
],
extrapolate: 'clamp',
}
),
},
{
translateY: _touchY.interpolate(
{
inputRange: [
0,
containerSize?.height ||
0,
],
outputRange: [
0,
containerSize?.height ||
0,
],
extrapolate: 'clamp',
}
),
},
],
translateX: pan.x.interpolate( {
inputRange: [
0,
containerSize?.width || 0,
],
outputRange: [
0,
containerSize?.width || 0,
],
extrapolate: 'clamp',
} ),
},
] }
>
<SVG
style={ styles.focalPointIcon }
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 30 30"
>
<Path
style={
styles.focalPointIconPathOutline
}
d="M15 1C7.3 1 1 7.3 1 15s6.3 14 14 14 14-6.3 14-14S22.7 1 15 1zm0 22c-4.4 0-8-3.6-8-8s3.6-8 8-8 8 3.6 8 8-3.6 8-8 8z"
/>
<Path
style={ styles.focalPointIconPathFill }
d="M15 3C8.4 3 3 8.4 3 15s5.4 12 12 12 12-5.4 12-12S21.6 3 15 3zm0 22C9.5 25 5 20.5 5 15S9.5 5 15 5s10 4.5 10 10-4.5 10-10 10z"
/>
</SVG>
</Animated.View>
</Animated.View>
</PanGestureHandler>
</TapGestureHandler>
{
translateY: pan.y.interpolate( {
inputRange: [
0,
containerSize?.height || 0,
],
outputRange: [
0,
containerSize?.height || 0,
],
extrapolate: 'clamp',
} ),
},
],
},
] }
>
<SVG
style={ styles.focalPointIcon }
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 30 30"
>
<Path
style={ styles.focalPointIconPathOutline }
d="M15 1C7.3 1 1 7.3 1 15s6.3 14 14 14 14-6.3 14-14S22.7 1 15 1zm0 22c-4.4 0-8-3.6-8-8s3.6-8 8-8 8 3.6 8 8-3.6 8-8 8z"
/>
<Path
style={ styles.focalPointIconPathFill }
d="M15 3C8.4 3 3 8.4 3 15s5.4 12 12 12 12-5.4 12-12S21.6 3 15 3zm0 22C9.5 25 5 20.5 5 15S9.5 5 15 5s10 4.5 10 10-4.5 10-10 10z"
/>
</SVG>
</Animated.View>
</View>
</View>
<RangeControl
inputSuffix="%"
Expand Down

0 comments on commit 49c6cb4

Please sign in to comment.