Skip to content

Commit 471c19f

Browse files
committed
feat(toast): adjust different height case animation
1 parent 690659c commit 471c19f

File tree

6 files changed

+93
-64
lines changed

6 files changed

+93
-64
lines changed

example/src/app/(home)/components/toast.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ import { UsageVariantFlatList } from '../../../components/component-presentation
7777

7878
const MyToast1 = (props: ToastComponentProps) => {
7979
const { id, hide } = props;
80-
console.log('🔴 id 🔴', id); // VS remove
8180

8281
return (
8382
<Toast
@@ -100,7 +99,6 @@ const MyToast1 = (props: ToastComponentProps) => {
10099

101100
const MyToast2 = (props: ToastComponentProps) => {
102101
const { id, hide } = props;
103-
console.log('🔴 id 🔴', id); // VS remove
104102

105103
return (
106104
<Toast
@@ -125,7 +123,6 @@ const MyToast2 = (props: ToastComponentProps) => {
125123

126124
const MyToast3 = (props: ToastComponentProps) => {
127125
const { id, hide } = props;
128-
console.log('🔴 id 🔴', id); // VS remove
129126

130127
return (
131128
<Toast

src/components/toast/toast.animation.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ export function useToastRootAnimation(options: {
7575
animation: ToastRootAnimation | undefined;
7676
style: ViewStyle | undefined;
7777
index: number;
78-
total: number;
79-
heights: SharedValue<number[]>;
78+
total: SharedValue<number>;
79+
heights: SharedValue<Record<string, number>>;
8080
placement: ToastPlacement;
8181
hide?: ((ids?: string | string[]) => void) | undefined;
8282
id?: string | undefined;
@@ -295,7 +295,9 @@ export function useToastRootAnimation(options: {
295295
const lastToastId = Object.keys(heights.get())[
296296
Object.keys(heights.get()).length - 1
297297
];
298-
const lastToastHeight = heights.get()[lastToastId];
298+
const lastToastHeight = lastToastId
299+
? heights.get()[lastToastId]
300+
: undefined;
299301

300302
const sign = placement === 'top' ? 1 : -1;
301303

src/components/toast/toast.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ const ToastRoot = forwardRef<ViewRef, ToastRootProps>((props, ref) => {
3535
const {
3636
children,
3737
variant = 'default',
38+
duration = 4000,
3839
placement = 'top',
3940
index,
4041
total,
4142
heights,
4243
className,
4344
style,
4445
animation,
45-
duration = 4000,
46-
hide,
4746
isSwipable,
47+
hide,
4848
...restProps
4949
} = props;
5050

@@ -108,10 +108,9 @@ const ToastRoot = forwardRef<ViewRef, ToastRootProps>((props, ref) => {
108108
style={[styleSheet.root, style]}
109109
onLayout={(event) => {
110110
const measuredHeight = event.nativeEvent.layout.height;
111-
heights.modify((value: Record<string, number>) => {
111+
heights.modify((value) => {
112112
'worklet';
113-
value[id] = measuredHeight;
114-
return value;
113+
return { ...value, [id]: measuredHeight };
115114
});
116115
}}
117116
{...restProps}

src/providers/toast/provider.tsx

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const ToasterContext = createContext<ToasterContextValue | null>(null);
2929
export function ToastProvider({ insets, children }: ToastProviderProps) {
3030
const [toasts, dispatch] = useReducer(toastReducer, []);
3131

32+
const isToastVisible = toasts.length > 0;
33+
3234
const heights = useSharedValue<Record<string, number>>({});
3335

3436
const total = useSharedValue<number>(0);
@@ -38,57 +40,58 @@ export function ToastProvider({ insets, children }: ToastProviderProps) {
3840
/**
3941
* Show a toast
4042
*/
41-
const show = useCallback((options: ToastShowOptions): string => {
42-
const id = options.id ?? `toast-${Date.now()}-${idCounter.current++}`;
43-
44-
dispatch({
45-
type: 'SHOW',
46-
payload: {
47-
id,
48-
component: options.component,
49-
},
50-
});
51-
52-
total.set((value) => value + 1);
43+
const show = useCallback(
44+
(options: ToastShowOptions): string => {
45+
const id = options.id ?? `toast-${Date.now()}-${idCounter.current++}`;
5346

54-
return id;
55-
}, []);
56-
57-
/**
58-
* Hide one or more toasts
59-
*/
60-
const hide = useCallback((ids?: string | string[]) => {
61-
if (ids === undefined) {
62-
// Hide all toasts
63-
dispatch({ type: 'HIDE_ALL' });
64-
heights.set({});
65-
total.set(0);
66-
} else {
67-
// Hide specific toast(s)
68-
const idsArray = Array.isArray(ids) ? ids : [ids];
69-
const idsToRemove = idsArray;
7047
dispatch({
71-
type: 'HIDE',
72-
payload: { ids: idsArray },
48+
type: 'SHOW',
49+
payload: {
50+
id,
51+
component: options.component,
52+
},
7353
});
7454

75-
heights.modify(<T extends Record<string, number>>(value: T): T => {
76-
'worklet';
77-
const result = { ...value };
78-
for (const id of idsToRemove) {
79-
delete result[id];
80-
}
81-
return result;
82-
});
55+
total.set((value) => value + 1);
8356

84-
total.set((value) => value - 1);
85-
}
86-
}, []);
57+
return id;
58+
},
59+
[total]
60+
);
8761

8862
/**
89-
* Whether any toast is currently visible
63+
* Hide one or more toasts
9064
*/
91-
const isToastVisible = toasts.length > 0;
65+
const hide = useCallback(
66+
(ids?: string | string[]) => {
67+
if (ids === undefined) {
68+
// Hide all toasts
69+
dispatch({ type: 'HIDE_ALL' });
70+
heights.set({});
71+
total.set(0);
72+
} else {
73+
// Hide specific toast(s)
74+
const idsArray = Array.isArray(ids) ? ids : [ids];
75+
const idsToRemove = idsArray;
76+
dispatch({
77+
type: 'HIDE',
78+
payload: { ids: idsArray },
79+
});
80+
81+
heights.modify(<T extends Record<string, number>>(value: T): T => {
82+
'worklet';
83+
const result = { ...value };
84+
for (const id of idsToRemove) {
85+
delete result[id];
86+
}
87+
return result;
88+
});
89+
90+
total.set((value) => value - 1);
91+
}
92+
},
93+
[total, heights]
94+
);
9295

9396
const contextValue = useMemo<ToasterContextValue>(
9497
() => ({

src/providers/toast/toast-item-renderer.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import { memo } from 'react';
2-
import type { ToastItem, ToastShowOptions } from './types';
3-
4-
interface ToastItemRendererProps {
5-
toastItem: ToastItem;
6-
index: number;
7-
total: number;
8-
show: (options: ToastShowOptions) => string;
9-
hide: (ids?: string | string[]) => void;
10-
}
2+
import type { ToastItemRendererProps } from './types';
113

124
/**
135
* Memoized toast item component to prevent unnecessary re-renders

src/providers/toast/types.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { SharedValue } from 'react-native-reanimated';
2+
13
/**
24
* Insets for spacing from screen edges
35
*/
@@ -56,7 +58,11 @@ export interface ToastComponentProps {
5658
/**
5759
* The total number of toasts currently displayed
5860
*/
59-
total: number;
61+
total: SharedValue<number>;
62+
/**
63+
* Heights of all toast items, keyed by toast ID
64+
*/
65+
heights: SharedValue<Record<string, number>>;
6066
/**
6167
* Show a new toast
6268
*/
@@ -146,6 +152,36 @@ export interface ToastManager {
146152
hide: (ids?: string | string[]) => void;
147153
}
148154

155+
/**
156+
* Props for the ToastItemRenderer component
157+
*/
158+
export interface ToastItemRendererProps {
159+
/**
160+
* The toast item to render
161+
*/
162+
toastItem: ToastItem;
163+
/**
164+
* The index of the toast in the array (0-based)
165+
*/
166+
index: number;
167+
/**
168+
* The total number of toasts currently displayed
169+
*/
170+
total: SharedValue<number>;
171+
/**
172+
* Heights of all toast items, keyed by toast ID
173+
*/
174+
heights: SharedValue<Record<string, number>>;
175+
/**
176+
* Show a new toast
177+
*/
178+
show: (options: ToastShowOptions) => string;
179+
/**
180+
* Hide one or more toasts
181+
*/
182+
hide: (ids?: string | string[]) => void;
183+
}
184+
149185
/**
150186
* Context value for the toast provider
151187
*/

0 commit comments

Comments
 (0)