Skip to content

Commit

Permalink
fix: resume animation on interruption (#769)
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhom committed Dec 5, 2021
1 parent cb373ef commit f2a9332
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ import {
useBottomSheetGestureHandlers,
useBottomSheetInternal,
} from '../../hooks';
import { GESTURE_SOURCE } from '../../constants';
import type { BottomSheetDraggableViewProps } from './types';
import { styles } from './styles';

const BottomSheetDraggableViewComponent = ({
gestureType = GESTURE_SOURCE.CONTENT,
nativeGestureRef,
refreshControlGestureRef,
style,
children,
...rest
}: BottomSheetDraggableViewProps) => {
// refs
const panGestureRef = useRef<PanGestureHandler>(null);

// hooks
//#region hooks
const {
enableContentPanningGesture,
simultaneousHandlers: _providedSimultaneousHandlers,
Expand All @@ -28,9 +27,19 @@ const BottomSheetDraggableViewComponent = ({
failOffsetX,
failOffsetY,
} = useBottomSheetInternal();
const { contentPanGestureHandler } = useBottomSheetGestureHandlers();
const { contentPanGestureHandler, scrollablePanGestureHandler } =
useBottomSheetGestureHandlers();
//#endregion

// variables
//#region variables
const panGestureRef = useRef<PanGestureHandler>(null);
const gestureHandler = useMemo(
() =>
gestureType === GESTURE_SOURCE.CONTENT
? contentPanGestureHandler
: scrollablePanGestureHandler,
[gestureType, contentPanGestureHandler, scrollablePanGestureHandler]
);
const simultaneousHandlers = useMemo(() => {
const refs = [];

Expand All @@ -56,19 +65,19 @@ const BottomSheetDraggableViewComponent = ({
nativeGestureRef,
refreshControlGestureRef,
]);
//#endregion

// styles
//#region styles
const containerStyle = useMemo(() => {
if (!style) {
return styles.container;
}

if (Array.isArray(style)) {
return [styles.container, ...style];
}

return [styles.container, style];
}, [style]);
//#endregion

return (
<PanGestureHandler
Expand All @@ -77,7 +86,7 @@ const BottomSheetDraggableViewComponent = ({
simultaneousHandlers={simultaneousHandlers}
shouldCancelWhenOutside={false}
waitFor={waitFor}
onGestureEvent={contentPanGestureHandler}
onGestureEvent={gestureHandler}
activeOffsetX={activeOffsetX}
activeOffsetY={activeOffsetY}
failOffsetX={failOffsetX}
Expand Down
9 changes: 8 additions & 1 deletion src/components/bottomSheetDraggableView/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { ReactNode, Ref } from 'react';
import type { ViewProps as RNViewProps } from 'react-native';
import type { NativeViewGestureHandler } from 'react-native-gesture-handler';
import type { GESTURE_SOURCE } from '../../constants';

export type BottomSheetDraggableViewProps = RNViewProps & {
children: React.ReactNode[] | React.ReactNode;
/**
* Defines the gesture type of the draggable view.
*
* @default GESTURE_SOURCE.CONTENT
* @type GESTURE_SOURCE
*/
gestureType?: GESTURE_SOURCE;
nativeGestureRef?: Ref<NativeViewGestureHandler> | null;
refreshControlGestureRef?: Ref<NativeViewGestureHandler> | null;
children: ReactNode[] | ReactNode;
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,71 @@ import {
} from '../../hooks';
import { BottomSheetGestureHandlersContext } from '../../contexts';
import type { BottomSheetGestureHandlersProviderProps } from './types';
import { useSharedValue } from 'react-native-reanimated';

const BottomSheetGestureHandlersProvider = ({
gestureEventsHandlersHook:
useGestureEventsHandlers = useGestureEventsHandlersDefault,
children,
}: BottomSheetGestureHandlersProviderProps) => {
// hooks
//#region variables
const animatedGestureSource = useSharedValue<GESTURE_SOURCE>(
GESTURE_SOURCE.UNDETERMINED
);
//#endregion

//#region hooks
const { animatedContentGestureState, animatedHandleGestureState } =
useBottomSheetInternal();
const { handleOnStart, handleOnActive, handleOnEnd } =
useGestureEventsHandlers();
//#endregion

// gestures
//#region gestures
const contentPanGestureHandler = useGestureHandler(
GESTURE_SOURCE.CONTENT,
animatedContentGestureState,
animatedGestureSource,
handleOnStart,
handleOnActive,
handleOnEnd
);

const scrollablePanGestureHandler = useGestureHandler(
GESTURE_SOURCE.SCROLLABLE,
animatedContentGestureState,
animatedGestureSource,
handleOnStart,
handleOnActive,
handleOnEnd
);

const handlePanGestureHandler = useGestureHandler(
GESTURE_SOURCE.HANDLE,
animatedHandleGestureState,
animatedGestureSource,
handleOnStart,
handleOnActive,
handleOnEnd
);
//#endregion

// context value
//#region context
const contextValue = useMemo(
() => ({ contentPanGestureHandler, handlePanGestureHandler }),
[contentPanGestureHandler, handlePanGestureHandler]
() => ({
contentPanGestureHandler,
handlePanGestureHandler,
scrollablePanGestureHandler,
animatedGestureSource,
}),
[
contentPanGestureHandler,
handlePanGestureHandler,
scrollablePanGestureHandler,
animatedGestureSource,
]
);
//#endregion
return (
<BottomSheetGestureHandlersContext.Provider value={contextValue}>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
useBottomSheetInternal,
} from '../../hooks';
import {
GESTURE_SOURCE,
SCROLLABLE_DECELERATION_RATE_MAPPER,
SCROLLABLE_STATE,
SCROLLABLE_TYPE,
Expand Down Expand Up @@ -122,6 +123,7 @@ export function createBottomSheetScrollableComponent<T, P>(
<BottomSheetDraggableView
nativeGestureRef={nativeGestureRef}
refreshControlGestureRef={refreshControlGestureRef}
gestureType={GESTURE_SOURCE.SCROLLABLE}
style={styles.container}
>
{onRefresh ? (
Expand All @@ -143,6 +145,7 @@ export function createBottomSheetScrollableComponent<T, P>(
return (
<BottomSheetDraggableView
nativeGestureRef={nativeGestureRef}
gestureType={GESTURE_SOURCE.SCROLLABLE}
style={styles.container}
>
<NativeViewGestureHandler
Expand Down
4 changes: 3 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ const { height: WINDOW_HEIGHT, width: WINDOW_WIDTH } = Dimensions.get('window');
const { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get('screen');

enum GESTURE_SOURCE {
SCROLLABLE = 0,
UNDETERMINED = 0,
SCROLLABLE,
HANDLE,
CONTENT,
}

enum SHEET_STATE {
Expand Down
1 change: 1 addition & 0 deletions src/contexts/gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { PanGestureHandlerGestureEvent } from 'react-native-gesture-handler
export interface BottomSheetGestureHandlersContextType {
contentPanGestureHandler: (event: PanGestureHandlerGestureEvent) => void;
handlePanGestureHandler: (event: PanGestureHandlerGestureEvent) => void;
scrollablePanGestureHandler: (event: PanGestureHandlerGestureEvent) => void;
}

export const BottomSheetGestureHandlersContext =
Expand Down
104 changes: 78 additions & 26 deletions src/hooks/useGestureHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,93 @@ import {
PanGestureHandlerGestureEvent,
} from 'react-native-gesture-handler';
import { GESTURE_SOURCE } from '../constants';
import type { GestureEventHandlerCallbackType } from '../types';
import type {
GestureEventContextType,
GestureEventHandlerCallbackType,
} from '../types';

const resetContext = (context: any) => {
'worklet';

Object.keys(context).map(key => {
context[key] = undefined;
});
};

export const useGestureHandler = (
type: GESTURE_SOURCE,
state: Animated.SharedValue<State>,
gestureSource: Animated.SharedValue<GESTURE_SOURCE>,
handleOnStart: GestureEventHandlerCallbackType,
handleOnActive: GestureEventHandlerCallbackType,
handleOnEnd: GestureEventHandlerCallbackType
): ((event: PanGestureHandlerGestureEvent) => void) => {
const gestureHandler =
useAnimatedGestureHandler<PanGestureHandlerGestureEvent>(
{
onStart: (payload, context) => {
state.value = payload.state;
const gestureHandler = useAnimatedGestureHandler<
PanGestureHandlerGestureEvent,
GestureEventContextType
>(
{
onActive: (payload, context) => {
if (!context.didStart) {
context.didStart = true;

state.value = State.BEGAN;
gestureSource.value = type;

handleOnStart(type, payload, context);
},
onActive: (payload, context) => {
state.value = payload.state;
handleOnActive(type, payload, context);
},
onEnd: (payload, context) => {
state.value = payload.state;
handleOnEnd(type, payload, context);
},
onCancel: payload => {
state.value = payload.state;
},
onFail: payload => {
state.value = payload.state;
},
onFinish: payload => {
state.value = payload.state;
},
return;
}

if (gestureSource.value !== type) {
return;
}

state.value = payload.state;
handleOnActive(type, payload, context);
},
onEnd: (payload, context) => {
if (gestureSource.value !== type) {
return;
}

state.value = payload.state;
gestureSource.value = GESTURE_SOURCE.UNDETERMINED;

handleOnEnd(type, payload, context);
resetContext(context);
},
onCancel: (payload, context) => {
if (gestureSource.value !== type) {
return;
}

state.value = payload.state;
gestureSource.value = GESTURE_SOURCE.UNDETERMINED;

resetContext(context);
},
onFail: (payload, context) => {
if (gestureSource.value !== type) {
return;
}

state.value = payload.state;
gestureSource.value = GESTURE_SOURCE.UNDETERMINED;

resetContext(context);
},
onFinish: (payload, context) => {
if (gestureSource.value !== type) {
return;
}

state.value = payload.state;
gestureSource.value = GESTURE_SOURCE.UNDETERMINED;

resetContext(context);
},
[type, state, handleOnStart, handleOnActive, handleOnEnd]
);
},
[type, state, handleOnStart, handleOnActive, handleOnEnd]
);
return gestureHandler;
};
6 changes: 5 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ export interface Insets {
export type GestureEventPayloadType = GestureEventPayload &
PanGestureHandlerEventPayload;

type GestureEventHandlerCallbackType<C = any> = (
export type GestureEventContextType = {
didStart?: boolean;
};

export type GestureEventHandlerCallbackType<C = any> = (
source: GESTURE_SOURCE,
payload: GestureEventPayloadType,
context: C
Expand Down

0 comments on commit f2a9332

Please sign in to comment.