Skip to content

Commit

Permalink
fix: gesture touch area tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnartorfis committed Sep 5, 2024
1 parent 2a93629 commit cabb95e
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 88 deletions.
31 changes: 9 additions & 22 deletions src/animations.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,43 @@
import { useToastContext } from './context';
import { ToastPosition } from './types';
import React from 'react';
import { Easing, withTiming } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useToastContext } from './context';
import { ToastPosition } from './types';

export const ANIMATION_DURATION = 300;
const easing = Easing.inOut(Easing.ease);
const animationOptions = { duration: ANIMATION_DURATION, easing };

export const useToastLayoutAnimations = () => {
const { position } = useToastContext();
const insets = useSafeAreaInsets();

return React.useMemo(
() => ({
entering: () => {
'worklet';
return getToastEntering({ position, insets });
return getToastEntering({ position });
},
exiting: () => {
'worklet';
return getToastExiting({ position, insets });
return getToastExiting({ position });
},
}),
[insets, position]
[position]
);
};

type GetToastAnimationParams = {
position: ToastPosition;
insets: ReturnType<typeof useSafeAreaInsets>;
};

export const getToastEntering = ({
position,
insets,
}: GetToastAnimationParams) => {
export const getToastEntering = ({ position }: GetToastAnimationParams) => {
'worklet';

const animations = {
opacity: withTiming(1, animationOptions),
transform: [
{ scale: withTiming(1, animationOptions) },
{
translateY: withTiming(
position === ToastPosition.TOP_CENTER ? insets.top : -insets.bottom,
animationOptions
),
translateY: withTiming(0, animationOptions),
},
],
};
Expand All @@ -67,10 +58,7 @@ export const getToastEntering = ({
};
};

export const getToastExiting = ({
position,
insets,
}: GetToastAnimationParams) => {
export const getToastExiting = ({ position }: GetToastAnimationParams) => {
'worklet';

const animations = {
Expand All @@ -91,8 +79,7 @@ export const getToastExiting = ({
transform: [
{ scale: 1 },
{
translateY:
position === ToastPosition.TOP_CENTER ? insets.top : -insets.bottom,
translateY: 0,
},
],
};
Expand Down
16 changes: 12 additions & 4 deletions src/gestures.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { ANIMATION_DURATION } from './animations';
import { useToastContext } from './context';
import { ToastSwipeDirection } from './types';
import * as React from 'react';
import { Dimensions, type ViewStyle } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
Expand All @@ -13,6 +10,9 @@ import Animated, {
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import { ANIMATION_DURATION } from './animations';
import { useToastContext } from './context';
import { ToastSwipeDirection } from './types';

const { LEFT, UP } = ToastSwipeDirection;

Expand Down Expand Up @@ -105,7 +105,15 @@ export const ToastSwipeHandler: React.FC<
return (
<GestureDetector gesture={pan}>
<Animated.View
style={[animatedStyle, { width: '100%' }, style]}
style={[
animatedStyle,
{
width: '100%',
justifyContent: 'center',
marginBottom: 16,
},
style,
]}
className={className}
layout={LinearTransition.duration(ANIMATION_DURATION)}
>
Expand Down
17 changes: 8 additions & 9 deletions src/toast.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useColors } from './use-colors';
import { ANIMATION_DURATION, useToastLayoutAnimations } from './animations';
import { useToastContext } from './context';
import { ToastSwipeHandler } from './gestures';
import { ToastVariant, type ToastProps } from './types';
import { CircleCheck, CircleX, Info, X } from 'lucide-react-native';
import * as React from 'react';
import { ActivityIndicator, Pressable, Text, View } from 'react-native';
import Animated from 'react-native-reanimated';
import { ANIMATION_DURATION, useToastLayoutAnimations } from './animations';
import { useToastContext } from './context';
import { ToastSwipeHandler } from './gestures';
import { ToastVariant, type ToastProps } from './types';
import { useColors } from './use-colors';

export const Toast: React.FC<ToastProps> = ({
id,
Expand Down Expand Up @@ -36,6 +36,7 @@ export const Toast: React.FC<ToastProps> = ({
const duration = durationProps ?? durationContext;

const colors = useColors();
const { entering, exiting } = useToastLayoutAnimations();

const isDragging = React.useRef(false);
const timer = React.useRef<NodeJS.Timeout>();
Expand Down Expand Up @@ -77,8 +78,6 @@ export const Toast: React.FC<ToastProps> = ({
return () => clearTimeout(timer.current);
}, [duration, id, onHide, promiseOptions, updateToast]);

const { entering, exiting } = useToastLayoutAnimations();

return (
<ToastSwipeHandler
onRemove={() => {
Expand Down Expand Up @@ -107,15 +106,15 @@ export const Toast: React.FC<ToastProps> = ({
className={className}
style={[
elevationStyle,
style,
{
justifyContent: 'center',
padding: 16,
borderRadius: 16,
marginBottom: 16,
marginHorizontal: 16,
backgroundColor: colors['background-primary'],
borderCurve: 'continuous',
},
style,
]}
entering={entering}
exiting={exiting}
Expand Down
121 changes: 68 additions & 53 deletions src/toaster.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import * as React from 'react';
import { View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { FullWindowOverlay } from 'react-native-screens';
import { v4 as uuidv4 } from 'uuid';
import { toastDefaultValues } from './constants';
import { ToastContext } from './context';
import { Toast } from './toast';
import {
ToastPosition,
type ToastFunctionBase,
Expand All @@ -7,20 +14,21 @@ import {
type ToastProviderProps,
type ToastUpdateFunction,
} from './types';
import { toastDefaultValues } from './constants';
import * as React from 'react';
import { View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { FullWindowOverlay } from 'react-native-screens';
import { v4 as uuidv4 } from 'uuid';
import { Toast } from './toast';

let addToastHandler: ToastFunctionBase;
let updateToastHandler: ToastUpdateFunction;

const { TOP_CENTER, BOTTOM_CENTER } = ToastPosition;

export const Toaster: React.FC<ToastProviderProps> = ({
export const Toaster: React.FC<ToastProviderProps> = (props) => {
return (
<FullWindowOverlay>
<ToasterUI {...props} />
</FullWindowOverlay>
);
};

export const ToasterUI: React.FC<ToastProviderProps> = ({
duration,
position,
maxToasts = 3,
Expand All @@ -35,6 +43,7 @@ export const Toaster: React.FC<ToastProviderProps> = ({
}) => {
const [toasts, setToasts] = React.useState<ToastProps[]>([]);
const { top, bottom } = useSafeAreaInsets();
console.log(top, bottom, position);

addToastHandler = (title, options?: ToastFunctionOptions) => {
const id = uuidv4();
Expand Down Expand Up @@ -97,52 +106,58 @@ export const Toaster: React.FC<ToastProviderProps> = ({
: toasts.slice().reverse();
}, [position, toasts]);

const insetValues = React.useMemo(() => {
if (position === BOTTOM_CENTER) {
if (bottom > 0) {
return { bottom };
}
return { bottom: 40 };
}

if (position === TOP_CENTER) {
if (top > 0) {
return { top };
}
return { top: 40 };
}

console.warn('Invalid position value');
return {};
}, [position, bottom, top]);

return (
<FullWindowOverlay>
<ToastContext.Provider value={value}>
<View
style={[
{
position: 'absolute',
width: '100%',
alignItems: 'center',
bottom:
position === BOTTOM_CENTER && bottom > 0
? 0
: position === BOTTOM_CENTER && bottom === 0
? 40
: undefined,
top:
position === TOP_CENTER && top > 0
? 0
: position === TOP_CENTER && top === 0
? 40
: undefined,
},
rootStyle,
]}
className={rootClassName}
>
{positionedToasts.map((toast) => {
return (
<Toast
key={toast.id}
{...toast}
onHide={() => {
removeToast(toast.id);
toast.onHide?.();
}}
className={toastContentClassName}
style={toastContentStyle}
containerStyle={toastContainerStyle}
containerClassName={toastContainerClassName}
{...props}
/>
);
})}
</View>
</ToastContext.Provider>
</FullWindowOverlay>
<ToastContext.Provider value={value}>
<View
style={[
{
position: 'absolute',
width: '100%',
alignItems: 'center',
},
insetValues,
rootStyle,
]}
className={rootClassName}
>
{positionedToasts.map((toast) => {
return (
<Toast
key={toast.id}
{...toast}
onHide={() => {
removeToast(toast.id);
toast.onHide?.();
}}
className={toastContentClassName}
style={toastContentStyle}
containerStyle={toastContainerStyle}
containerClassName={toastContainerClassName}
{...props}
/>
);
})}
</View>
</ToastContext.Provider>
);
};

Expand Down

0 comments on commit cabb95e

Please sign in to comment.