react-native-bread 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +2 -1
  2. package/lib/commonjs/icons/CloseIcon.js +1 -22
  3. package/lib/commonjs/icons/GreenCheck.js +1 -27
  4. package/lib/commonjs/icons/InfoIcon.js +1 -24
  5. package/lib/commonjs/icons/RedX.js +1 -27
  6. package/lib/commonjs/icons/index.js +1 -34
  7. package/lib/commonjs/index.js +1 -59
  8. package/lib/commonjs/toast-api.js +1 -127
  9. package/lib/commonjs/toast-provider.js +1 -66
  10. package/lib/commonjs/toast-store.js +1 -278
  11. package/lib/commonjs/toast.js +1 -481
  12. package/lib/commonjs/types.js +1 -6
  13. package/lib/module/icons/CloseIcon.js +1 -16
  14. package/lib/module/icons/GreenCheck.js +1 -21
  15. package/lib/module/icons/InfoIcon.js +1 -18
  16. package/lib/module/icons/RedX.js +1 -21
  17. package/lib/module/icons/index.js +1 -7
  18. package/lib/module/index.js +1 -14
  19. package/lib/module/toast-api.js +1 -124
  20. package/lib/module/toast-provider.js +1 -62
  21. package/lib/module/toast-store.js +1 -274
  22. package/lib/module/toast.js +1 -475
  23. package/lib/module/types.js +1 -4
  24. package/package.json +7 -6
  25. package/lib/commonjs/icons/CloseIcon.js.map +0 -1
  26. package/lib/commonjs/icons/GreenCheck.js.map +0 -1
  27. package/lib/commonjs/icons/InfoIcon.js.map +0 -1
  28. package/lib/commonjs/icons/RedX.js.map +0 -1
  29. package/lib/commonjs/icons/index.js.map +0 -1
  30. package/lib/commonjs/index.js.map +0 -1
  31. package/lib/commonjs/toast-api.js.map +0 -1
  32. package/lib/commonjs/toast-provider.js.map +0 -1
  33. package/lib/commonjs/toast-store.js.map +0 -1
  34. package/lib/commonjs/toast.js.map +0 -1
  35. package/lib/commonjs/types.js.map +0 -1
  36. package/lib/module/icons/CloseIcon.js.map +0 -1
  37. package/lib/module/icons/GreenCheck.js.map +0 -1
  38. package/lib/module/icons/InfoIcon.js.map +0 -1
  39. package/lib/module/icons/RedX.js.map +0 -1
  40. package/lib/module/icons/index.js.map +0 -1
  41. package/lib/module/index.js.map +0 -1
  42. package/lib/module/toast-api.js.map +0 -1
  43. package/lib/module/toast-provider.js.map +0 -1
  44. package/lib/module/toast-store.js.map +0 -1
  45. package/lib/module/toast.js.map +0 -1
  46. package/lib/module/types.js.map +0 -1
  47. package/lib/typescript/icons/CloseIcon.d.ts.map +0 -1
  48. package/lib/typescript/icons/GreenCheck.d.ts.map +0 -1
  49. package/lib/typescript/icons/InfoIcon.d.ts.map +0 -1
  50. package/lib/typescript/icons/RedX.d.ts.map +0 -1
  51. package/lib/typescript/icons/index.d.ts.map +0 -1
  52. package/lib/typescript/index.d.ts.map +0 -1
  53. package/lib/typescript/toast-api.d.ts.map +0 -1
  54. package/lib/typescript/toast-provider.d.ts.map +0 -1
  55. package/lib/typescript/toast-store.d.ts.map +0 -1
  56. package/lib/typescript/toast.d.ts.map +0 -1
  57. package/lib/typescript/types.d.ts.map +0 -1
  58. package/src/icons/CloseIcon.tsx +0 -10
  59. package/src/icons/GreenCheck.tsx +0 -16
  60. package/src/icons/InfoIcon.tsx +0 -12
  61. package/src/icons/RedX.tsx +0 -16
  62. package/src/icons/index.ts +0 -4
  63. package/src/index.ts +0 -26
  64. package/src/toast-api.ts +0 -213
  65. package/src/toast-provider.tsx +0 -77
  66. package/src/toast-store.ts +0 -270
  67. package/src/toast.tsx +0 -466
  68. package/src/types.ts +0 -121
package/src/toast.tsx DELETED
@@ -1,466 +0,0 @@
1
- import { memo, type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import { ActivityIndicator, Pressable, StyleSheet, Text, View } from "react-native";
3
- import { Gesture, GestureDetector } from "react-native-gesture-handler";
4
- import Animated, {
5
- Easing,
6
- interpolate,
7
- useAnimatedStyle,
8
- useDerivedValue,
9
- useSharedValue,
10
- withTiming,
11
- } from "react-native-reanimated";
12
- import { useSafeAreaInsets } from "react-native-safe-area-context";
13
- import { scheduleOnRN } from "react-native-worklets";
14
- import { CloseIcon, GreenCheck, InfoIcon, RedX } from "./icons";
15
- import { type Toast as ToastData, type ToastState, type ToastType, toastStore } from "./toast-store";
16
- import type { IconRenderFn, ToastPosition, ToastTheme } from "./types";
17
-
18
- const ICON_SIZE = 28;
19
-
20
- /** Memoized default icons to prevent SVG re-renders */
21
- const MemoizedGreenCheck = memo(({ fill }: { fill: string }) => <GreenCheck width={36} height={36} fill={fill} />);
22
- const MemoizedRedX = memo(({ fill }: { fill: string }) => <RedX width={ICON_SIZE} height={ICON_SIZE} fill={fill} />);
23
- const MemoizedInfoIcon = memo(({ fill }: { fill: string }) => (
24
- <InfoIcon width={ICON_SIZE} height={ICON_SIZE} fill={fill} />
25
- ));
26
- const MemoizedCloseIcon = memo(() => <CloseIcon width={20} height={20} />);
27
-
28
- /** Default icon for each toast type - memoized */
29
- const DefaultIcon = memo(({ type, accentColor }: { type: ToastType; accentColor: string }) => {
30
- switch (type) {
31
- case "success":
32
- return <MemoizedGreenCheck fill={accentColor} />;
33
- case "error":
34
- return <MemoizedRedX fill={accentColor} />;
35
- case "loading":
36
- return <ActivityIndicator size={ICON_SIZE} color={accentColor} />;
37
- case "info":
38
- return <MemoizedInfoIcon fill={accentColor} />;
39
- default:
40
- return <MemoizedGreenCheck fill={accentColor} />;
41
- }
42
- });
43
-
44
- interface AnimatedIconProps {
45
- type: ToastType;
46
- accentColor: string;
47
- customIcon?: ReactNode | IconRenderFn;
48
- configIcon?: IconRenderFn;
49
- }
50
-
51
- /** Resolves the icon to render - checks per-toast, then config, then default */
52
- const resolveIcon = (
53
- type: ToastType,
54
- accentColor: string,
55
- customIcon?: ReactNode | IconRenderFn,
56
- configIcon?: IconRenderFn
57
- ): ReactNode => {
58
- if (customIcon) {
59
- if (typeof customIcon === "function") {
60
- return customIcon({ color: accentColor, size: ICON_SIZE });
61
- }
62
- return customIcon;
63
- }
64
- if (configIcon) {
65
- return configIcon({ color: accentColor, size: ICON_SIZE });
66
- }
67
- return <DefaultIcon type={type} accentColor={accentColor} />;
68
- };
69
-
70
- /** Animated icon wrapper with scale/fade animation */
71
- const AnimatedIcon = memo(({ type, accentColor, customIcon, configIcon }: AnimatedIconProps) => {
72
- const progress = useSharedValue(0);
73
-
74
- useEffect(() => {
75
- progress.value = withTiming(1, { duration: 350, easing: Easing.out(Easing.back(1.5)) });
76
- }, [progress]);
77
-
78
- const style = useAnimatedStyle(() => ({
79
- opacity: progress.value,
80
- transform: [{ scale: 0.7 + progress.value * 0.3 }],
81
- }));
82
-
83
- return <Animated.View style={style}>{resolveIcon(type, accentColor, customIcon, configIcon)}</Animated.View>;
84
- });
85
-
86
- interface ToastContentProps {
87
- type: ToastType;
88
- title: string;
89
- description?: string;
90
- accentColor: string;
91
- customIcon?: ReactNode | IconRenderFn;
92
- configIcon?: IconRenderFn;
93
- showCloseButton: boolean;
94
- onDismiss: () => void;
95
- titleStyle?: object;
96
- descriptionStyle?: object;
97
- optionsTitleStyle?: object;
98
- optionsDescriptionStyle?: object;
99
- }
100
-
101
- /** Memoized toast content to prevent inline JSX recreation */
102
- const ToastContent = memo(
103
- ({
104
- type,
105
- title,
106
- description,
107
- accentColor,
108
- customIcon,
109
- configIcon,
110
- showCloseButton,
111
- onDismiss,
112
- titleStyle,
113
- descriptionStyle,
114
- optionsTitleStyle,
115
- optionsDescriptionStyle,
116
- }: ToastContentProps) => (
117
- <View style={styles.content}>
118
- <View style={styles.icon}>
119
- <AnimatedIcon key={type} type={type} accentColor={accentColor} customIcon={customIcon} configIcon={configIcon} />
120
- </View>
121
- <View style={styles.textContainer}>
122
- <Text
123
- maxFontSizeMultiplier={1.35}
124
- allowFontScaling={false}
125
- style={[styles.title, { color: accentColor }, titleStyle, optionsTitleStyle]}
126
- >
127
- {title}
128
- </Text>
129
- {description && (
130
- <Text
131
- allowFontScaling={false}
132
- maxFontSizeMultiplier={1.35}
133
- style={[styles.description, descriptionStyle, optionsDescriptionStyle]}
134
- >
135
- {description}
136
- </Text>
137
- )}
138
- </View>
139
- {showCloseButton && (
140
- <Pressable style={styles.closeButton} onPress={onDismiss} hitSlop={12}>
141
- <MemoizedCloseIcon />
142
- </Pressable>
143
- )}
144
- </View>
145
- )
146
- );
147
-
148
- // singleton instance
149
- export const ToastContainer = () => {
150
- const [visibleToasts, setVisibleToasts] = useState<ToastData[]>([]);
151
- const [theme, setTheme] = useState<ToastTheme>(() => toastStore.getTheme());
152
- const { top, bottom } = useSafeAreaInsets();
153
-
154
- useEffect(() => {
155
- const initialState = toastStore.getState();
156
- setVisibleToasts(initialState.visibleToasts);
157
- setTheme(toastStore.getTheme());
158
-
159
- return toastStore.subscribe((state: ToastState) => {
160
- setVisibleToasts(state.visibleToasts);
161
- setTheme(toastStore.getTheme());
162
- });
163
- }, []);
164
-
165
- // Calculate visual index for each toast (exiting toasts don't count)
166
- const getVisualIndex = useCallback(
167
- (toastId: string) => {
168
- let visualIndex = 0;
169
- for (const t of visibleToasts) {
170
- if (t.id === toastId) break;
171
- if (!t.isExiting) visualIndex++;
172
- }
173
- return visualIndex;
174
- },
175
- [visibleToasts]
176
- );
177
-
178
- // Memoize the reversed array to avoid recreating on each render
179
- const reversedToasts = useMemo(() => [...visibleToasts].reverse(), [visibleToasts]);
180
-
181
- if (visibleToasts.length === 0) {
182
- return null;
183
- }
184
-
185
- const isBottom = theme.position === "bottom";
186
- const inset = isBottom ? bottom : top;
187
- const positionStyle = isBottom ? { bottom: inset + theme.offset + 2 } : { top: inset + theme.offset + 2 };
188
-
189
- return (
190
- <View style={[styles.container, positionStyle]} pointerEvents="box-none">
191
- {reversedToasts.map(toast => {
192
- const index = toast.isExiting ? -1 : getVisualIndex(toast.id);
193
- return <MemoizedToastItem key={toast.id} toast={toast} index={index} theme={theme} position={theme.position} />;
194
- })}
195
- </View>
196
- );
197
- };
198
-
199
- interface ToastItemProps {
200
- toast: ToastData;
201
- index: number;
202
- theme: ToastTheme;
203
- position: ToastPosition;
204
- }
205
-
206
- const EASING = Easing.bezier(0.25, 0.1, 0.25, 1.0);
207
- const ToY = 0;
208
- const Duration = 400;
209
- const ExitDuration = 350;
210
- const MaxDragDown = 60;
211
-
212
- const ToastItem = ({ toast, index, theme, position }: ToastItemProps) => {
213
- const progress = useSharedValue(0);
214
- const translationY = useSharedValue(0);
215
- const isBeingDragged = useSharedValue(false);
216
- const shouldDismiss = useSharedValue(false);
217
-
218
- // Position-based animation values
219
- const isBottom = position === "bottom";
220
- const entryFromY = isBottom ? 80 : -80;
221
- const exitToY = isBottom ? 100 : -100;
222
-
223
- // Stack position animation
224
- const stackIndex = useSharedValue(index);
225
-
226
- // Refs for tracking previous values to avoid unnecessary animations
227
- const lastHandledType = useRef(toast.type);
228
- const prevIndex = useRef(index);
229
- const hasEntered = useRef(false);
230
-
231
- useEffect(() => {
232
- // Entry animation (only once on mount)
233
- if (!hasEntered.current && !toast.isExiting) {
234
- progress.value = withTiming(1, { duration: Duration, easing: EASING });
235
- hasEntered.current = true;
236
- }
237
-
238
- // Exit animation when isExiting becomes true
239
- if (toast.isExiting) {
240
- progress.value = withTiming(0, { duration: ExitDuration, easing: EASING });
241
- translationY.value = withTiming(exitToY, { duration: ExitDuration, easing: EASING });
242
- }
243
-
244
- // Track type changes (for icon animation via key)
245
- if (toast.type !== lastHandledType.current) {
246
- lastHandledType.current = toast.type;
247
- }
248
-
249
- // Stack position animation when index changes
250
- if (index >= 0 && prevIndex.current !== index) {
251
- stackIndex.value = withTiming(index, { duration: 300, easing: EASING });
252
- prevIndex.current = index;
253
- }
254
- }, [toast.isExiting, toast.type, index, progress, translationY, stackIndex, exitToY]);
255
-
256
- const dismissToast = useCallback(() => {
257
- toastStore.hide(toast.id);
258
- }, [toast.id]);
259
-
260
- const panGesture = useMemo(
261
- () =>
262
- Gesture.Pan()
263
- .onStart(() => {
264
- "worklet";
265
- isBeingDragged.value = true;
266
- shouldDismiss.value = false;
267
- })
268
- .onUpdate(event => {
269
- "worklet";
270
- const rawY = event.translationY;
271
- // For top: negative Y = dismiss direction, positive Y = resistance
272
- // For bottom: positive Y = dismiss direction, negative Y = resistance
273
- const dismissDrag = isBottom ? rawY : -rawY;
274
- const resistDrag = isBottom ? -rawY : rawY;
275
-
276
- if (dismissDrag > 0) {
277
- // Moving toward dismiss direction
278
- const clampedY = isBottom ? Math.min(rawY, 180) : Math.max(rawY, -180);
279
- translationY.value = clampedY;
280
- if (dismissDrag > 40 || (isBottom ? event.velocityY > 300 : event.velocityY < -300)) {
281
- shouldDismiss.value = true;
282
- }
283
- } else {
284
- // Moving away from edge - apply resistance
285
- const exponentialDrag = MaxDragDown * (1 - Math.exp(-resistDrag / 250));
286
- translationY.value = isBottom
287
- ? -Math.min(exponentialDrag, MaxDragDown)
288
- : Math.min(exponentialDrag, MaxDragDown);
289
- shouldDismiss.value = false;
290
- }
291
- })
292
- .onEnd(() => {
293
- "worklet";
294
- isBeingDragged.value = false;
295
-
296
- if (shouldDismiss.value) {
297
- progress.value = withTiming(0, {
298
- duration: ExitDuration,
299
- easing: EASING,
300
- });
301
- const exitOffset = isBottom ? 200 : -200;
302
- translationY.value = withTiming(translationY.value + exitOffset, {
303
- duration: ExitDuration,
304
- easing: EASING,
305
- });
306
- scheduleOnRN(dismissToast);
307
- } else {
308
- translationY.value = withTiming(0, {
309
- duration: 650,
310
- easing: EASING,
311
- });
312
- }
313
- }),
314
- [isBottom, dismissToast, progress, translationY, shouldDismiss, isBeingDragged]
315
- );
316
-
317
- // Memoize disabled gesture to avoid recreation on every render
318
- const disabledGesture = useMemo(() => Gesture.Pan().enabled(false), []);
319
-
320
- // Derive zIndex separately - it's not animatable and shouldn't trigger worklet re-runs
321
- const zIndex = useDerivedValue(() => 1000 - Math.round(stackIndex.value));
322
-
323
- const animatedStyle = useAnimatedStyle(() => {
324
- const baseTranslateY = interpolate(progress.value, [0, 1], [entryFromY, ToY]);
325
-
326
- // Stack offset: each toast behind moves away from edge (up for top, down for bottom)
327
- const stackOffsetY = isBottom ? stackIndex.value * 10 : stackIndex.value * -10;
328
-
329
- // Stack scale: each toast behind scales down by 0.05
330
- const stackScale = 1 - stackIndex.value * 0.05;
331
-
332
- const finalTranslateY = baseTranslateY + translationY.value + stackOffsetY;
333
-
334
- const progressOpacity = interpolate(progress.value, [0, 1], [0, 1]);
335
- // For top: dragging up (negative) fades out. For bottom: dragging down (positive) fades out
336
- const dismissDirection = isBottom ? translationY.value : -translationY.value;
337
- const dragOpacity = dismissDirection > 0 ? interpolate(dismissDirection, [0, 130], [1, 0], "clamp") : 1;
338
- const opacity = progressOpacity * dragOpacity;
339
-
340
- const dragScale = interpolate(Math.abs(translationY.value), [0, 50], [1, 0.98], "clamp");
341
- const scale = stackScale * dragScale;
342
-
343
- return {
344
- transform: [{ translateY: finalTranslateY }, { scale }],
345
- opacity,
346
- zIndex: zIndex.value,
347
- };
348
- });
349
-
350
- const accentColor = theme.colors[toast.type].accent;
351
- const backgroundColor = theme.colors[toast.type].background;
352
- const verticalAnchor = isBottom ? { bottom: 0 } : { top: 0 };
353
-
354
- // Per-toast overrides from options
355
- const { options } = toast;
356
- const customIcon = options?.icon;
357
- const configIcon = theme.icons[toast.type];
358
-
359
- // Resolve dismissible and showCloseButton (per-toast overrides config)
360
- const isDismissible = options?.dismissible ?? theme.dismissible;
361
- const shouldShowCloseButton = toast.type !== "loading" && (options?.showCloseButton ?? theme.showCloseButton);
362
-
363
- // Enable/disable gesture based on dismissible setting
364
- const gesture = isDismissible ? panGesture : disabledGesture;
365
-
366
- const animStyle = [
367
- styles.toast,
368
- verticalAnchor,
369
- { backgroundColor },
370
- theme.toastStyle,
371
- options?.style,
372
- animatedStyle,
373
- ];
374
-
375
- return (
376
- <GestureDetector gesture={gesture}>
377
- <Animated.View style={animStyle}>
378
- <ToastContent
379
- type={toast.type}
380
- title={toast.title}
381
- description={toast.description}
382
- accentColor={accentColor}
383
- customIcon={customIcon}
384
- configIcon={configIcon}
385
- showCloseButton={shouldShowCloseButton}
386
- onDismiss={dismissToast}
387
- titleStyle={theme.titleStyle}
388
- descriptionStyle={theme.descriptionStyle}
389
- optionsTitleStyle={options?.titleStyle}
390
- optionsDescriptionStyle={options?.descriptionStyle}
391
- />
392
- </Animated.View>
393
- </GestureDetector>
394
- );
395
- };
396
-
397
- // Custom comparison to prevent re-renders when toast object reference changes but content is same
398
- const MemoizedToastItem = memo(ToastItem, (prev, next) => {
399
- return (
400
- prev.toast.id === next.toast.id &&
401
- prev.toast.type === next.toast.type &&
402
- prev.toast.title === next.toast.title &&
403
- prev.toast.description === next.toast.description &&
404
- prev.toast.isExiting === next.toast.isExiting &&
405
- prev.index === next.index &&
406
- prev.position === next.position &&
407
- prev.theme === next.theme
408
- );
409
- });
410
-
411
- const styles = StyleSheet.create({
412
- container: {
413
- position: "absolute",
414
- left: 16,
415
- right: 16,
416
- zIndex: 1000,
417
- },
418
- closeButton: {
419
- padding: 4,
420
- alignItems: "center",
421
- justifyContent: "center",
422
- },
423
- icon: {
424
- width: 48,
425
- height: 48,
426
- alignItems: "center",
427
- justifyContent: "center",
428
- marginLeft: 8,
429
- },
430
- content: {
431
- alignItems: "center",
432
- flexDirection: "row",
433
- gap: 12,
434
- minHeight: 36,
435
- },
436
- description: {
437
- color: "#6B7280",
438
- fontSize: 12,
439
- fontWeight: "500",
440
- lineHeight: 16,
441
- },
442
- textContainer: {
443
- flex: 1,
444
- gap: 1,
445
- justifyContent: "center",
446
- },
447
- title: {
448
- fontSize: 14,
449
- fontWeight: "700",
450
- lineHeight: 20,
451
- },
452
- toast: {
453
- borderRadius: 20,
454
- borderCurve: "continuous",
455
- position: "absolute",
456
- left: 0,
457
- right: 0,
458
- paddingHorizontal: 12,
459
- paddingVertical: 10,
460
- shadowColor: "#000",
461
- shadowOffset: { width: 0, height: 8 },
462
- shadowOpacity: 0.05,
463
- shadowRadius: 24,
464
- elevation: 8,
465
- },
466
- });
package/src/types.ts DELETED
@@ -1,121 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import type { TextStyle, ViewStyle } from "react-native";
3
-
4
- export type ToastType = "success" | "error" | "info" | "loading";
5
-
6
- export type ToastPosition = "top" | "bottom";
7
-
8
- export interface ToastTypeColors {
9
- /** Accent color used for title text and icons */
10
- accent: string;
11
- /** Background color of the toast */
12
- background: string;
13
- }
14
-
15
- /** Props passed to custom icon render functions */
16
- export interface IconProps {
17
- /** The accent color from the theme for this toast type */
18
- color: string;
19
- /** Default icon size */
20
- size: number;
21
- }
22
-
23
- /** Custom icon render function */
24
- export type IconRenderFn = (props: IconProps) => ReactNode;
25
-
26
- export interface ToastTheme {
27
- /** Position of toasts on screen */
28
- position: ToastPosition;
29
- /** Extra offset from safe area edge (in addition to safe area insets) */
30
- offset: number;
31
- /** Whether to show multiple toasts stacked (default: true). When false, only one toast shows at a time. */
32
- stacking: boolean;
33
- /** Maximum number of toasts visible at once when stacking is enabled (default: 3) */
34
- maxStack: number;
35
- /** Whether toasts can be dismissed via swipe gesture (default: true) */
36
- dismissible: boolean;
37
- /** Whether to show the close button on toasts (default: true). Loading toasts never show close button. */
38
- showCloseButton: boolean;
39
- /** Colors for each toast type */
40
- colors: Record<ToastType, ToastTypeColors>;
41
- /** Custom icons for each toast type */
42
- icons: Partial<Record<ToastType, IconRenderFn>>;
43
- /** Style overrides for the toast container */
44
- toastStyle: ViewStyle;
45
- /** Style overrides for the title text */
46
- titleStyle: TextStyle;
47
- /** Style overrides for the description text */
48
- descriptionStyle: TextStyle;
49
- /** Default duration in ms for toasts (default: 4000) */
50
- defaultDuration: number;
51
- }
52
-
53
- /** Per-toast options for customizing individual toasts */
54
- export interface ToastOptions {
55
- /** Description text */
56
- description?: string;
57
- /** Duration in ms (overrides default) */
58
- duration?: number;
59
- /** Custom icon (ReactNode or render function) */
60
- icon?: ReactNode | IconRenderFn;
61
- /** Style overrides for this toast's container */
62
- style?: ViewStyle;
63
- /** Style overrides for this toast's title */
64
- titleStyle?: TextStyle;
65
- /** Style overrides for this toast's description */
66
- descriptionStyle?: TextStyle;
67
- /** Whether this toast can be dismissed via swipe (overrides config) */
68
- dismissible?: boolean;
69
- /** Whether to show the close button on this toast (overrides config) */
70
- showCloseButton?: boolean;
71
- }
72
-
73
- /** Configuration options for customizing toast behavior and appearance. All properties are optional. */
74
- export type ToastConfig = {
75
- [K in keyof ToastTheme]?: K extends "colors"
76
- ? Partial<Record<ToastType, Partial<ToastTypeColors>>>
77
- : K extends "icons"
78
- ? Partial<Record<ToastType, IconRenderFn>>
79
- : ToastTheme[K];
80
- };
81
-
82
- export interface Toast {
83
- id: string;
84
- title: string;
85
- description?: string;
86
- type: ToastType;
87
- duration: number;
88
- createdAt: number;
89
- isExiting?: boolean;
90
- /** Per-toast style/icon overrides */
91
- options?: ToastOptions;
92
- }
93
-
94
- export interface ToastState {
95
- /** Visible toasts (index 0 = front/newest) */
96
- visibleToasts: Toast[];
97
- }
98
-
99
- // --- Promise helper types ---
100
- export type MessageInput =
101
- | string
102
- | {
103
- title: string;
104
- description?: string;
105
- /** Override duration (ms) after promise settles */
106
- duration?: number;
107
- };
108
-
109
- export type ErrorMessageInput = MessageInput | ((error: Error) => MessageInput);
110
-
111
- export interface PromiseMessages {
112
- loading: MessageInput;
113
- success: MessageInput;
114
- error: ErrorMessageInput;
115
- }
116
-
117
- export interface PromiseResult<T> {
118
- data?: T;
119
- error?: Error;
120
- success: boolean;
121
- }