Skip to content

Commit 9afd9c7

Browse files
committed
fix: update to allow for more granular customizability
1 parent de127e6 commit 9afd9c7

File tree

6 files changed

+110
-34
lines changed

6 files changed

+110
-34
lines changed

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ toast('Hello World', {
264264
text: TextStyle,
265265
indicator: ViewStyle
266266
},
267+
animationType: 'timing' | 'spring',
268+
animationConfig: {
269+
flingPositionReturnDuration: number,
270+
...(springConfig | timingConfig)
271+
},
267272
});
268273
```
269274

@@ -402,6 +407,63 @@ Every type has its own duration. You can overwrite them `duration` with the toas
402407

403408
<br />
404409

410+
### Animation Options
411+
You can now control the animation type and configuration for toasts.
412+
413+
#### Props
414+
415+
- **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.
416+
- **animationConfig** (object, optional): Customize the animation configuration for spring or timing.
417+
418+
#### Example Usage
419+
420+
```javascript
421+
import { toast } from 'react-native-toast';
422+
423+
// Show a toast with custom animation settings
424+
toast.show('This is a toast message', {
425+
animationType: 'spring',
426+
animationConfig: {
427+
duration: 500,
428+
stiffness: 100,
429+
},
430+
position: 'top',
431+
});
432+
````
433+
434+
### Global Animation Configuration/Type
435+
436+
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.
437+
438+
#### Props
439+
440+
- **globalAnimationConfig** (object, optional): Provides a default configuration for toast animations using either spring or timing options.
441+
442+
#### Example Usage
443+
444+
```javascript
445+
import { Toasts } from 'react-native-toast';
446+
447+
// In your component
448+
<Toasts
449+
globalAnimationType="spring"
450+
globalAnimationConfig={{
451+
duration: 500,
452+
stiffness: 120,
453+
}}
454+
/>
455+
456+
// Or when showing a toast
457+
toast.show('This is a toast message', {
458+
position: 'bottom',
459+
animationType: 'spring',
460+
animationConfig: {
461+
duration: 400,
462+
damping: 10,
463+
},
464+
});
465+
```
466+
405467

406468
### Dismiss toast programmatically
407469

src/components/Toast.tsx

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,37 +116,32 @@ export const Toast: FC<Props> = ({
116116
}, []);
117117

118118
const setPosition = useCallback(() => {
119-
//control the position of the toast when rendering
120-
//based on offset, visibility, keyboard, and toast height
121-
let timingConfig: WithTimingConfig = {
122-
duration: 300,
123-
};
124-
let springConfig: WithSpringConfig = {
125-
stiffness: 80,
126-
};
119+
let timingConfig: WithTimingConfig = { duration: 300 };
120+
let springConfig: WithSpringConfig = { stiffness: 80 };
121+
127122
if (toast.animationConfig) {
128123
const {
129124
duration = 300,
130125
easing = Easing.inOut(Easing.quad),
131126
reduceMotion = ReduceMotion.System,
132127
...spring
133128
} = toast.animationConfig;
134-
timingConfig = {
135-
duration,
136-
easing,
137-
reduceMotion,
138-
};
129+
timingConfig = { duration, easing, reduceMotion };
139130
springConfig = spring;
140131
}
141132

133+
const useSpringAnimation = toast.animationType === 'spring';
134+
135+
const animation = useSpringAnimation ? withSpring : withTiming;
136+
142137
if (toast.position === ToastPosition.TOP) {
143-
offsetY.value = withTiming(
138+
offsetY.value = animation(
144139
toast.visible ? offset : startingY,
145-
timingConfig
140+
useSpringAnimation ? springConfig : timingConfig
146141
);
147-
position.value = withTiming(
142+
position.value = animation(
148143
toast.visible ? offset : startingY,
149-
timingConfig
144+
useSpringAnimation ? springConfig : timingConfig
150145
);
151146
} else {
152147
let kbHeight = keyboardVisible ? keyboardHeight : 0;
@@ -160,9 +155,14 @@ export const Toast: FC<Props> = ({
160155
24
161156
: startingY;
162157

163-
offsetY.value = withSpring(val, springConfig);
164-
165-
position.value = withSpring(val, springConfig);
158+
offsetY.value = animation(
159+
val,
160+
useSpringAnimation ? springConfig : timingConfig
161+
);
162+
position.value = animation(
163+
val,
164+
useSpringAnimation ? springConfig : timingConfig
165+
);
166166
}
167167
}, [
168168
offset,
@@ -177,6 +177,7 @@ export const Toast: FC<Props> = ({
177177
offsetY,
178178
extraInsets,
179179
toast.animationConfig,
180+
toast.animationType,
180181
]);
181182

182183
const composedGesture = useMemo(() => {
@@ -215,19 +216,16 @@ export const Toast: FC<Props> = ({
215216
]);
216217

217218
useEffect(() => {
218-
//set the toast height if it updates while rendered
219219
setToastHeight(toast?.height ? toast.height : DEFAULT_TOAST_HEIGHT);
220220
}, [toast.height]);
221221

222222
useEffect(() => {
223-
//set the toast width if it updates while rendered
224223
setToastWidth(
225224
toast?.width ? toast.width : width - 32 > 360 ? 360 : width - 32
226225
);
227226
}, [toast.width, width]);
228227

229228
useEffect(() => {
230-
//Control visibility of toast when rendering
231229
opacity.value = withTiming(toast.visible ? 1 : 0, {
232230
duration: toast?.animationConfig?.duration ?? 300,
233231
});

src/components/Toasts.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { TextStyle, View, ViewStyle } from 'react-native';
44
import { Toast as T, useToaster } from '../headless';
55
import { Toast } from './Toast';
66
import { useSafeAreaInsets } from 'react-native-safe-area-context';
7-
import { ExtraInsets } from '../core/types';
7+
import {
8+
ExtraInsets,
9+
ToastAnimationConfig,
10+
ToastAnimationType,
11+
} from '../core/types';
812
import { useScreenReader } from 'src/core/utils';
913

1014
type Props = {
@@ -21,6 +25,8 @@ type Props = {
2125
text?: TextStyle;
2226
indicator?: ViewStyle;
2327
};
28+
globalAnimationType?: ToastAnimationType;
29+
globalAnimationConfig?: ToastAnimationConfig;
2430
};
2531

2632
export const Toasts: FunctionComponent<Props> = ({
@@ -32,6 +38,8 @@ export const Toasts: FunctionComponent<Props> = ({
3238
providerKey = 'DEFAULT',
3339
preventScreenReaderFromHiding,
3440
defaultStyle,
41+
globalAnimationType,
42+
globalAnimationConfig,
3543
}) => {
3644
const { toasts, handlers } = useToaster({ providerKey });
3745
const { startPause, endPause } = handlers;
@@ -56,7 +64,11 @@ export const Toasts: FunctionComponent<Props> = ({
5664
{toasts.map((t) => (
5765
<Toast
5866
key={t.id}
59-
toast={t}
67+
toast={{
68+
...t,
69+
animationType: t.animationType || globalAnimationType,
70+
animationConfig: t.animationConfig || globalAnimationConfig,
71+
}}
6072
startPause={startPause}
6173
endPause={endPause}
6274
updateHeight={handlers.updateHeight}

src/core/toast.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const createToast = (
2828
position: ToastPosition.TOP,
2929
providerKey: 'DEFAULT',
3030
isSwipeable: true,
31+
animationType: opts?.animationType ?? 'timing',
32+
animationConfig: opts?.animationConfig,
3133
...opts,
3234
id: opts?.id || genId(),
3335
});

src/core/types.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import type { TextStyle, ViewStyle } from 'react-native';
2-
import type {
3-
WithTimingConfig,
4-
WithSpringConfig,
5-
} from 'react-native-reanimated';
2+
import { WithSpringConfig, WithTimingConfig } from 'react-native-reanimated';
63

74
export type ToastType = 'success' | 'error' | 'loading' | 'blank';
85
export enum ToastPosition {
@@ -16,6 +13,12 @@ export interface IconTheme {
1613
primary: string;
1714
secondary: string;
1815
}
16+
export type ToastAnimationType = 'spring' | 'timing';
17+
18+
export type ToastAnimationConfig = {
19+
flingPositionReturnDuration?: number;
20+
} & WithSpringConfig &
21+
WithTimingConfig;
1922

2023
export type ValueFunction<TValue, TArg> = (arg: TArg) => TValue;
2124
export type ValueOrFunction<TValue, TArg> =
@@ -55,10 +58,8 @@ export interface Toast {
5558
customToast?: (toast: Toast) => JSX.Element;
5659
providerKey: string;
5760
isSwipeable?: boolean;
58-
animationConfig?: {
59-
flingPositionReturnDuration?: number;
60-
} & WithSpringConfig &
61-
WithTimingConfig;
61+
animationType?: ToastAnimationType;
62+
animationConfig?: ToastAnimationConfig;
6263
}
6364

6465
export type ToastOptions = Partial<
@@ -77,6 +78,7 @@ export type ToastOptions = Partial<
7778
| 'providerKey'
7879
| 'isSwipeable'
7980
| 'animationConfig'
81+
| 'animationType'
8082
>
8183
>;
8284

src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { useToaster } from './core/use-toaster';
22
export { Toasts } from './components';
33
export * from './headless';
4-
export { ToastPosition } from './core/types';
4+
export { ToastPosition, ToastAnimationType } from './core/types';

0 commit comments

Comments
 (0)