diff --git a/README.md b/README.md
index 6dc8e31..b087ed9 100644
--- a/README.md
+++ b/README.md
@@ -264,6 +264,11 @@ toast('Hello World', {
text: TextStyle,
indicator: ViewStyle
},
+ animationType: 'timing' | 'spring',
+ animationConfig: {
+ flingPositionReturnDuration: number,
+ ...(springConfig | timingConfig)
+ },
});
```
@@ -402,6 +407,63 @@ Every type has its own duration. You can overwrite them `duration` with the toas
+### Animation Options
+You can now control the animation type and configuration for toasts.
+
+#### Props
+
+- **animationType** (`'spring' | 'timing'`, optional): Choose the animation type for toast appearance. By default, toasts positioned at the bottom use spring, and those at the top use timing.
+- **animationConfig** (object, optional): Customize the animation configuration for spring or timing.
+
+#### Example Usage
+
+```javascript
+import { toast } from 'react-native-toast';
+
+// Show a toast with custom animation settings
+toast.show('This is a toast message', {
+ animationType: 'spring',
+ animationConfig: {
+ duration: 500,
+ stiffness: 100,
+ },
+ position: 'top',
+});
+````
+
+### Global Animation Configuration/Type
+
+You can define a `globalAnimationType` and a `globalAnimationConfig` that sets the default animation configuration for all toasts. If an individual toast specifies its own `animationConfig`, it will override this global setting.
+
+#### Props
+
+- **globalAnimationConfig** (object, optional): Provides a default configuration for toast animations using either spring or timing options.
+
+#### Example Usage
+
+```javascript
+import { Toasts } from 'react-native-toast';
+
+// In your component
+
+
+// Or when showing a toast
+toast.show('This is a toast message', {
+ position: 'bottom',
+ animationType: 'spring',
+ animationConfig: {
+ duration: 400,
+ damping: 10,
+ },
+});
+```
+
### Dismiss toast programmatically
diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx
index c598db6..d3fe565 100644
--- a/src/components/Toast.tsx
+++ b/src/components/Toast.tsx
@@ -10,11 +10,15 @@ import {
ViewStyle,
} from 'react-native';
import Animated, {
+ Easing,
+ ReduceMotion,
runOnJS,
useAnimatedStyle,
useSharedValue,
withSpring,
+ type WithSpringConfig,
withTiming,
+ type WithTimingConfig,
} from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
@@ -112,15 +116,33 @@ export const Toast: FC = ({
}, []);
const setPosition = useCallback(() => {
- //control the position of the toast when rendering
- //based on offset, visibility, keyboard, and toast height
+ let timingConfig: WithTimingConfig = { duration: 300 };
+ let springConfig: WithSpringConfig = { stiffness: 80 };
+
+ if (toast.animationConfig) {
+ const {
+ duration = 300,
+ easing = Easing.inOut(Easing.quad),
+ reduceMotion = ReduceMotion.System,
+ ...spring
+ } = toast.animationConfig;
+ timingConfig = { duration, easing, reduceMotion };
+ springConfig = spring;
+ }
+
+ const useSpringAnimation = toast.animationType === 'spring';
+
+ const animation = useSpringAnimation ? withSpring : withTiming;
+
if (toast.position === ToastPosition.TOP) {
- offsetY.value = withTiming(toast.visible ? offset : startingY, {
- duration: toast?.animationConfig?.animationDuration ?? 300,
- });
- position.value = withTiming(toast.visible ? offset : startingY, {
- duration: toast?.animationConfig?.animationDuration ?? 300,
- });
+ offsetY.value = animation(
+ toast.visible ? offset : startingY,
+ useSpringAnimation ? springConfig : timingConfig
+ );
+ position.value = animation(
+ toast.visible ? offset : startingY,
+ useSpringAnimation ? springConfig : timingConfig
+ );
} else {
let kbHeight = keyboardVisible ? keyboardHeight : 0;
const val = toast.visible
@@ -133,13 +155,14 @@ export const Toast: FC = ({
24
: startingY;
- offsetY.value = withSpring(val, {
- stiffness: toast?.animationConfig?.animationStiffness ?? 80,
- });
-
- position.value = withSpring(val, {
- stiffness: toast?.animationConfig?.animationStiffness ?? 80,
- });
+ offsetY.value = animation(
+ val,
+ useSpringAnimation ? springConfig : timingConfig
+ );
+ position.value = animation(
+ val,
+ useSpringAnimation ? springConfig : timingConfig
+ );
}
}, [
offset,
@@ -154,6 +177,7 @@ export const Toast: FC = ({
offsetY,
extraInsets,
toast.animationConfig,
+ toast.animationType,
]);
const composedGesture = useMemo(() => {
@@ -192,21 +216,18 @@ export const Toast: FC = ({
]);
useEffect(() => {
- //set the toast height if it updates while rendered
setToastHeight(toast?.height ? toast.height : DEFAULT_TOAST_HEIGHT);
}, [toast.height]);
useEffect(() => {
- //set the toast width if it updates while rendered
setToastWidth(
toast?.width ? toast.width : width - 32 > 360 ? 360 : width - 32
);
}, [toast.width, width]);
useEffect(() => {
- //Control visibility of toast when rendering
opacity.value = withTiming(toast.visible ? 1 : 0, {
- duration: toast?.animationConfig?.animationDuration ?? 300,
+ duration: toast?.animationConfig?.duration ?? 300,
});
}, [toast.visible, opacity, toast.animationConfig]);
diff --git a/src/components/Toasts.tsx b/src/components/Toasts.tsx
index 6ff719d..6396f7f 100644
--- a/src/components/Toasts.tsx
+++ b/src/components/Toasts.tsx
@@ -4,7 +4,11 @@ import { TextStyle, View, ViewStyle } from 'react-native';
import { Toast as T, useToaster } from '../headless';
import { Toast } from './Toast';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
-import { ExtraInsets } from '../core/types';
+import {
+ ExtraInsets,
+ ToastAnimationConfig,
+ ToastAnimationType,
+} from '../core/types';
import { useScreenReader } from 'src/core/utils';
type Props = {
@@ -21,6 +25,8 @@ type Props = {
text?: TextStyle;
indicator?: ViewStyle;
};
+ globalAnimationType?: ToastAnimationType;
+ globalAnimationConfig?: ToastAnimationConfig;
};
export const Toasts: FunctionComponent = ({
@@ -32,6 +38,8 @@ export const Toasts: FunctionComponent = ({
providerKey = 'DEFAULT',
preventScreenReaderFromHiding,
defaultStyle,
+ globalAnimationType,
+ globalAnimationConfig,
}) => {
const { toasts, handlers } = useToaster({ providerKey });
const { startPause, endPause } = handlers;
@@ -56,7 +64,11 @@ export const Toasts: FunctionComponent = ({
{toasts.map((t) => (
= (arg: TArg) => TValue;
export type ValueOrFunction =
@@ -51,11 +58,8 @@ export interface Toast {
customToast?: (toast: Toast) => JSX.Element;
providerKey: string;
isSwipeable?: boolean;
- animationConfig?: {
- flingPositionReturnDuration?: number;
- animationStiffness?: number;
- animationDuration?: number;
- };
+ animationType?: ToastAnimationType;
+ animationConfig?: ToastAnimationConfig;
}
export type ToastOptions = Partial<
@@ -74,6 +78,7 @@ export type ToastOptions = Partial<
| 'providerKey'
| 'isSwipeable'
| 'animationConfig'
+ | 'animationType'
>
>;
diff --git a/src/index.tsx b/src/index.tsx
index cc5b159..e48b3cf 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,4 +1,4 @@
export { useToaster } from './core/use-toaster';
export { Toasts } from './components';
export * from './headless';
-export { ToastPosition } from './core/types';
+export { ToastPosition, ToastAnimationType } from './core/types';