react-native-bread 0.6.1 → 0.7.0

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.
package/README.md CHANGED
@@ -16,9 +16,10 @@ An extremely lightweight, opinionated toast component for React Native.
16
16
  - Promise handling with automatic loading → success/error states
17
17
  - Toast stacking with configurable limits
18
18
  - **Works above modals** - automatic on iOS, simple setup on Android
19
- - **RTL support** - perfect for Arabic and other RTL languages
19
+ - **RTL support** - code-level RTL for when you're not using native RTL (`I18nManager`)
20
20
  - Completely customizable - colors, icons, styles, animations
21
21
  - Full Expo compatibility
22
+ - **React Compiler compatible** - uses `.set()` / `.value` API for shared values
22
23
 
23
24
 
24
25
 
@@ -181,7 +182,7 @@ Customize all toasts globally via the `config` prop on `<BreadLoaf />`:
181
182
  <BreadLoaf
182
183
  config={{
183
184
  position: 'bottom',
184
- rtl: false, // Enable for RTL languages
185
+ rtl: false, // Code-level RTL — not needed if using native RTL (I18nManager)
185
186
  stacking: true,
186
187
  maxStack: 3,
187
188
  defaultDuration: 4000,
@@ -61,10 +61,10 @@ const AnimatedIcon = exports.AnimatedIcon = /*#__PURE__*/(0, _react.memo)(({
61
61
  }) => {
62
62
  const progress = (0, _reactNativeReanimated.useSharedValue)(0);
63
63
  (0, _react.useEffect)(() => {
64
- progress.value = (0, _reactNativeReanimated.withTiming)(1, {
64
+ progress.set((0, _reactNativeReanimated.withTiming)(1, {
65
65
  duration: _constants.ICON_ANIMATION_DURATION,
66
66
  easing: _reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.back(1.5))
67
- });
67
+ }));
68
68
  }, [progress]);
69
69
  const style = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
70
70
  opacity: progress.value,
@@ -28,69 +28,69 @@ const ToastContainer = () => {
28
28
  theme,
29
29
  toastsWithIndex,
30
30
  isBottom,
31
- topToastRef,
32
- isBottomRef,
33
- isDismissibleRef
31
+ topToastMutable,
32
+ isBottomMutable,
33
+ isDismissibleMutable
34
34
  } = (0, _useToastState.useToastState)();
35
35
  const shouldDismiss = (0, _reactNativeReanimated.useSharedValue)(false);
36
- const panGesture = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().onStart(() => {
36
+ const panGesture = _reactNativeGestureHandler.Gesture.Pan().onStart(() => {
37
37
  "worklet";
38
38
 
39
39
  shouldDismiss.set(false);
40
40
  }).onUpdate(event => {
41
41
  "worklet";
42
42
 
43
- if (!isDismissibleRef.current.value) return;
44
- const ref = topToastRef.current.value;
43
+ if (!isDismissibleMutable.value) return;
44
+ const ref = topToastMutable.value;
45
45
  if (!ref) return;
46
46
  const {
47
47
  slot
48
48
  } = ref;
49
- const bottom = isBottomRef.current.value;
49
+ const bottom = isBottomMutable.value;
50
50
  const rawY = event.translationY;
51
51
  const dismissDrag = bottom ? rawY : -rawY;
52
52
  const resistDrag = bottom ? -rawY : rawY;
53
53
  if (dismissDrag > 0) {
54
54
  const clampedY = bottom ? Math.min(rawY, _constants.MAX_DRAG_CLAMP) : Math.max(rawY, -_constants.MAX_DRAG_CLAMP);
55
- slot.translationY.value = clampedY;
55
+ slot.translationY.set(clampedY);
56
56
  const shouldTriggerDismiss = dismissDrag > _constants.DISMISS_THRESHOLD || (bottom ? event.velocityY > _constants.DISMISS_VELOCITY_THRESHOLD : event.velocityY < -_constants.DISMISS_VELOCITY_THRESHOLD);
57
57
  shouldDismiss.set(shouldTriggerDismiss);
58
58
  } else {
59
59
  const exponentialDrag = _constants.MAX_DRAG_RESISTANCE * (1 - Math.exp(-resistDrag / 250));
60
- slot.translationY.value = bottom ? -Math.min(exponentialDrag, _constants.MAX_DRAG_RESISTANCE) : Math.min(exponentialDrag, _constants.MAX_DRAG_RESISTANCE);
61
- shouldDismiss.value = false;
60
+ slot.translationY.set(bottom ? -Math.min(exponentialDrag, _constants.MAX_DRAG_RESISTANCE) : Math.min(exponentialDrag, _constants.MAX_DRAG_RESISTANCE));
61
+ shouldDismiss.set(false);
62
62
  }
63
63
  }).onEnd(() => {
64
64
  "worklet";
65
65
 
66
- if (!isDismissibleRef.current.value) return;
67
- const ref = topToastRef.current.value;
66
+ if (!isDismissibleMutable.value) return;
67
+ const ref = topToastMutable.value;
68
68
  if (!ref) return;
69
69
  const {
70
70
  slot
71
71
  } = ref;
72
- const bottom = isBottomRef.current.value;
72
+ const bottom = isBottomMutable.value;
73
73
  if (shouldDismiss.value) {
74
- slot.progress.value = (0, _reactNativeReanimated.withTiming)(0, {
74
+ slot.progress.set((0, _reactNativeReanimated.withTiming)(0, {
75
75
  duration: _constants.EXIT_DURATION,
76
76
  easing: _constants.EASING
77
- });
77
+ }));
78
78
  const exitOffset = bottom ? _constants.SWIPE_EXIT_OFFSET : -_constants.SWIPE_EXIT_OFFSET;
79
- slot.translationY.value = (0, _reactNativeReanimated.withTiming)(slot.translationY.value + exitOffset, {
79
+ slot.translationY.set((0, _reactNativeReanimated.withTiming)(slot.translationY.value + exitOffset, {
80
80
  duration: _constants.EXIT_DURATION,
81
81
  easing: _constants.EASING
82
- });
82
+ }));
83
83
  (0, _reactNativeWorklets.scheduleOnRN)(ref.dismiss);
84
84
  } else {
85
- slot.translationY.value = (0, _reactNativeReanimated.withTiming)(0, {
85
+ slot.translationY.set((0, _reactNativeReanimated.withTiming)(0, {
86
86
  duration: _constants.SPRING_BACK_DURATION,
87
87
  easing: _constants.EASING
88
- });
88
+ }));
89
89
  }
90
- }), [shouldDismiss, isDismissibleRef, topToastRef, isBottomRef]);
90
+ });
91
91
  const registerTopToast = (0, _react.useCallback)(values => {
92
- topToastRef.current.value = values;
93
- }, [topToastRef]);
92
+ topToastMutable.set(values);
93
+ }, [topToastMutable]);
94
94
  if (visibleToasts.length === 0) return null;
95
95
  const inset = isBottom ? bottom : top;
96
96
  const positionStyle = isBottom ? {
@@ -137,13 +137,13 @@ const ToastItem = ({
137
137
 
138
138
  // biome-ignore lint/correctness/useExhaustiveDependencies: mount-only effect
139
139
  (0, _react.useEffect)(() => {
140
- slot.progress.value = 0;
141
- slot.translationY.value = 0;
142
- slot.stackIndex.value = index;
143
- slot.progress.value = (0, _reactNativeReanimated.withTiming)(1, {
140
+ slot.progress.set(0);
141
+ slot.translationY.set(0);
142
+ slot.stackIndex.set(index);
143
+ slot.progress.set((0, _reactNativeReanimated.withTiming)(1, {
144
144
  duration: _constants.ENTRY_DURATION,
145
145
  easing: _constants.EASING
146
- });
146
+ }));
147
147
  const iconTimeout = setTimeout(() => setShowIcon(true), 50);
148
148
  return () => {
149
149
  clearTimeout(iconTimeout);
@@ -157,20 +157,20 @@ const ToastItem = ({
157
157
  let loadingTimeout = null;
158
158
  if (toast.isExiting && !tracker.wasExiting) {
159
159
  tracker.wasExiting = true;
160
- slot.progress.value = (0, _reactNativeReanimated.withTiming)(0, {
160
+ slot.progress.set((0, _reactNativeReanimated.withTiming)(0, {
161
161
  duration: _constants.EXIT_DURATION,
162
162
  easing: _constants.EASING
163
- });
164
- slot.translationY.value = (0, _reactNativeReanimated.withTiming)(exitToY, {
163
+ }));
164
+ slot.translationY.set((0, _reactNativeReanimated.withTiming)(exitToY, {
165
165
  duration: _constants.EXIT_DURATION,
166
166
  easing: _constants.EASING
167
- });
167
+ }));
168
168
  }
169
169
  if (tracker.initialized && index !== tracker.prevIndex) {
170
- slot.stackIndex.value = (0, _reactNativeReanimated.withTiming)(index, {
170
+ slot.stackIndex.set((0, _reactNativeReanimated.withTiming)(index, {
171
171
  duration: _constants.STACK_TRANSITION_DURATION,
172
172
  easing: _constants.EASING
173
- });
173
+ }));
174
174
  }
175
175
  tracker.prevIndex = index;
176
176
  tracker.initialized = true;
@@ -10,9 +10,9 @@ var _toastStore = require("./toast-store.js");
10
10
  const useToastState = () => {
11
11
  const [visibleToasts, setVisibleToasts] = (0, _react.useState)([]);
12
12
  const [theme, setTheme] = (0, _react.useState)(() => _toastStore.toastStore.getTheme());
13
- const topToastRef = (0, _react.useRef)((0, _reactNativeReanimated.makeMutable)(null));
14
- const isBottomRef = (0, _react.useRef)((0, _reactNativeReanimated.makeMutable)(theme.position === "bottom"));
15
- const isDismissibleRef = (0, _react.useRef)((0, _reactNativeReanimated.makeMutable)(true));
13
+ const [topToastMutable] = (0, _react.useState)(() => (0, _reactNativeReanimated.makeMutable)(null));
14
+ const [isBottomMutable] = (0, _react.useState)(() => (0, _reactNativeReanimated.makeMutable)(theme.position === "bottom"));
15
+ const [isDismissibleMutable] = (0, _react.useState)(() => (0, _reactNativeReanimated.makeMutable)(true));
16
16
  const isBottom = theme.position === "bottom";
17
17
  const topToast = visibleToasts.find(t => !t.isExiting);
18
18
  const isTopDismissible = topToast?.options?.dismissible ?? theme.dismissible;
@@ -21,8 +21,8 @@ const useToastState = () => {
21
21
  const initialTheme = _toastStore.toastStore.getTheme();
22
22
  setVisibleToasts(initialToasts);
23
23
  const initialTopToast = initialToasts.find(t => !t.isExiting);
24
- isBottomRef.current.value = initialTheme.position === "bottom";
25
- isDismissibleRef.current.value = initialTopToast?.options?.dismissible ?? initialTheme.dismissible;
24
+ isBottomMutable.set(initialTheme.position === "bottom");
25
+ isDismissibleMutable.set(initialTopToast?.options?.dismissible ?? initialTheme.dismissible);
26
26
  let pendingToasts = null;
27
27
  let rafId = null;
28
28
  const unsubscribe = _toastStore.toastStore.subscribe(state => {
@@ -38,13 +38,13 @@ const useToastState = () => {
38
38
  rafId = null;
39
39
  setTheme(prev => prev === currentTheme ? prev : currentTheme);
40
40
  const topToast = currentToasts.find(t => !t.isExiting);
41
- isBottomRef.current.value = currentTheme.position === "bottom";
42
- isDismissibleRef.current.value = topToast?.options?.dismissible ?? currentTheme.dismissible;
41
+ isBottomMutable.set(currentTheme.position === "bottom");
42
+ isDismissibleMutable.set(topToast?.options?.dismissible ?? currentTheme.dismissible);
43
43
  });
44
44
  }
45
45
  });
46
46
  return unsubscribe;
47
- }, []);
47
+ }, [isBottomMutable, isDismissibleMutable]);
48
48
  const toastsWithIndex = (0, _react.useMemo)(() => {
49
49
  const indices = new Map();
50
50
  let visualIndex = 0;
@@ -63,9 +63,9 @@ const useToastState = () => {
63
63
  toastsWithIndex,
64
64
  isBottom,
65
65
  isTopDismissible,
66
- topToastRef,
67
- isBottomRef,
68
- isDismissibleRef
66
+ topToastMutable,
67
+ isBottomMutable,
68
+ isDismissibleMutable
69
69
  };
70
70
  };
71
71
  exports.useToastState = useToastState;
@@ -55,10 +55,10 @@ export const AnimatedIcon = /*#__PURE__*/memo(({
55
55
  }) => {
56
56
  const progress = useSharedValue(0);
57
57
  useEffect(() => {
58
- progress.value = withTiming(1, {
58
+ progress.set(withTiming(1, {
59
59
  duration: ICON_ANIMATION_DURATION,
60
60
  easing: Easing.out(Easing.back(1.5))
61
- });
61
+ }));
62
62
  }, [progress]);
63
63
  const style = useAnimatedStyle(() => ({
64
64
  opacity: progress.value,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import { memo, useCallback, useEffect, useMemo, useState } from "react";
3
+ import { memo, useCallback, useEffect, useState } from "react";
4
4
  import { Pressable, StyleSheet, Text, View } from "react-native";
5
5
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
6
6
  import Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
@@ -23,69 +23,69 @@ export const ToastContainer = () => {
23
23
  theme,
24
24
  toastsWithIndex,
25
25
  isBottom,
26
- topToastRef,
27
- isBottomRef,
28
- isDismissibleRef
26
+ topToastMutable,
27
+ isBottomMutable,
28
+ isDismissibleMutable
29
29
  } = useToastState();
30
30
  const shouldDismiss = useSharedValue(false);
31
- const panGesture = useMemo(() => Gesture.Pan().onStart(() => {
31
+ const panGesture = Gesture.Pan().onStart(() => {
32
32
  "worklet";
33
33
 
34
34
  shouldDismiss.set(false);
35
35
  }).onUpdate(event => {
36
36
  "worklet";
37
37
 
38
- if (!isDismissibleRef.current.value) return;
39
- const ref = topToastRef.current.value;
38
+ if (!isDismissibleMutable.value) return;
39
+ const ref = topToastMutable.value;
40
40
  if (!ref) return;
41
41
  const {
42
42
  slot
43
43
  } = ref;
44
- const bottom = isBottomRef.current.value;
44
+ const bottom = isBottomMutable.value;
45
45
  const rawY = event.translationY;
46
46
  const dismissDrag = bottom ? rawY : -rawY;
47
47
  const resistDrag = bottom ? -rawY : rawY;
48
48
  if (dismissDrag > 0) {
49
49
  const clampedY = bottom ? Math.min(rawY, MAX_DRAG_CLAMP) : Math.max(rawY, -MAX_DRAG_CLAMP);
50
- slot.translationY.value = clampedY;
50
+ slot.translationY.set(clampedY);
51
51
  const shouldTriggerDismiss = dismissDrag > DISMISS_THRESHOLD || (bottom ? event.velocityY > DISMISS_VELOCITY_THRESHOLD : event.velocityY < -DISMISS_VELOCITY_THRESHOLD);
52
52
  shouldDismiss.set(shouldTriggerDismiss);
53
53
  } else {
54
54
  const exponentialDrag = MAX_DRAG_RESISTANCE * (1 - Math.exp(-resistDrag / 250));
55
- slot.translationY.value = bottom ? -Math.min(exponentialDrag, MAX_DRAG_RESISTANCE) : Math.min(exponentialDrag, MAX_DRAG_RESISTANCE);
56
- shouldDismiss.value = false;
55
+ slot.translationY.set(bottom ? -Math.min(exponentialDrag, MAX_DRAG_RESISTANCE) : Math.min(exponentialDrag, MAX_DRAG_RESISTANCE));
56
+ shouldDismiss.set(false);
57
57
  }
58
58
  }).onEnd(() => {
59
59
  "worklet";
60
60
 
61
- if (!isDismissibleRef.current.value) return;
62
- const ref = topToastRef.current.value;
61
+ if (!isDismissibleMutable.value) return;
62
+ const ref = topToastMutable.value;
63
63
  if (!ref) return;
64
64
  const {
65
65
  slot
66
66
  } = ref;
67
- const bottom = isBottomRef.current.value;
67
+ const bottom = isBottomMutable.value;
68
68
  if (shouldDismiss.value) {
69
- slot.progress.value = withTiming(0, {
69
+ slot.progress.set(withTiming(0, {
70
70
  duration: EXIT_DURATION,
71
71
  easing: EASING
72
- });
72
+ }));
73
73
  const exitOffset = bottom ? SWIPE_EXIT_OFFSET : -SWIPE_EXIT_OFFSET;
74
- slot.translationY.value = withTiming(slot.translationY.value + exitOffset, {
74
+ slot.translationY.set(withTiming(slot.translationY.value + exitOffset, {
75
75
  duration: EXIT_DURATION,
76
76
  easing: EASING
77
- });
77
+ }));
78
78
  scheduleOnRN(ref.dismiss);
79
79
  } else {
80
- slot.translationY.value = withTiming(0, {
80
+ slot.translationY.set(withTiming(0, {
81
81
  duration: SPRING_BACK_DURATION,
82
82
  easing: EASING
83
- });
83
+ }));
84
84
  }
85
- }), [shouldDismiss, isDismissibleRef, topToastRef, isBottomRef]);
85
+ });
86
86
  const registerTopToast = useCallback(values => {
87
- topToastRef.current.value = values;
88
- }, [topToastRef]);
87
+ topToastMutable.set(values);
88
+ }, [topToastMutable]);
89
89
  if (visibleToasts.length === 0) return null;
90
90
  const inset = isBottom ? bottom : top;
91
91
  const positionStyle = isBottom ? {
@@ -131,13 +131,13 @@ const ToastItem = ({
131
131
 
132
132
  // biome-ignore lint/correctness/useExhaustiveDependencies: mount-only effect
133
133
  useEffect(() => {
134
- slot.progress.value = 0;
135
- slot.translationY.value = 0;
136
- slot.stackIndex.value = index;
137
- slot.progress.value = withTiming(1, {
134
+ slot.progress.set(0);
135
+ slot.translationY.set(0);
136
+ slot.stackIndex.set(index);
137
+ slot.progress.set(withTiming(1, {
138
138
  duration: ENTRY_DURATION,
139
139
  easing: EASING
140
- });
140
+ }));
141
141
  const iconTimeout = setTimeout(() => setShowIcon(true), 50);
142
142
  return () => {
143
143
  clearTimeout(iconTimeout);
@@ -151,20 +151,20 @@ const ToastItem = ({
151
151
  let loadingTimeout = null;
152
152
  if (toast.isExiting && !tracker.wasExiting) {
153
153
  tracker.wasExiting = true;
154
- slot.progress.value = withTiming(0, {
154
+ slot.progress.set(withTiming(0, {
155
155
  duration: EXIT_DURATION,
156
156
  easing: EASING
157
- });
158
- slot.translationY.value = withTiming(exitToY, {
157
+ }));
158
+ slot.translationY.set(withTiming(exitToY, {
159
159
  duration: EXIT_DURATION,
160
160
  easing: EASING
161
- });
161
+ }));
162
162
  }
163
163
  if (tracker.initialized && index !== tracker.prevIndex) {
164
- slot.stackIndex.value = withTiming(index, {
164
+ slot.stackIndex.set(withTiming(index, {
165
165
  duration: STACK_TRANSITION_DURATION,
166
166
  easing: EASING
167
- });
167
+ }));
168
168
  }
169
169
  tracker.prevIndex = index;
170
170
  tracker.initialized = true;
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
 
3
- import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { useEffect, useMemo, useState } from "react";
4
4
  import { makeMutable } from "react-native-reanimated";
5
5
  import { toastStore } from "./toast-store.js";
6
6
  export const useToastState = () => {
7
7
  const [visibleToasts, setVisibleToasts] = useState([]);
8
8
  const [theme, setTheme] = useState(() => toastStore.getTheme());
9
- const topToastRef = useRef(makeMutable(null));
10
- const isBottomRef = useRef(makeMutable(theme.position === "bottom"));
11
- const isDismissibleRef = useRef(makeMutable(true));
9
+ const [topToastMutable] = useState(() => makeMutable(null));
10
+ const [isBottomMutable] = useState(() => makeMutable(theme.position === "bottom"));
11
+ const [isDismissibleMutable] = useState(() => makeMutable(true));
12
12
  const isBottom = theme.position === "bottom";
13
13
  const topToast = visibleToasts.find(t => !t.isExiting);
14
14
  const isTopDismissible = topToast?.options?.dismissible ?? theme.dismissible;
@@ -17,8 +17,8 @@ export const useToastState = () => {
17
17
  const initialTheme = toastStore.getTheme();
18
18
  setVisibleToasts(initialToasts);
19
19
  const initialTopToast = initialToasts.find(t => !t.isExiting);
20
- isBottomRef.current.value = initialTheme.position === "bottom";
21
- isDismissibleRef.current.value = initialTopToast?.options?.dismissible ?? initialTheme.dismissible;
20
+ isBottomMutable.set(initialTheme.position === "bottom");
21
+ isDismissibleMutable.set(initialTopToast?.options?.dismissible ?? initialTheme.dismissible);
22
22
  let pendingToasts = null;
23
23
  let rafId = null;
24
24
  const unsubscribe = toastStore.subscribe(state => {
@@ -34,13 +34,13 @@ export const useToastState = () => {
34
34
  rafId = null;
35
35
  setTheme(prev => prev === currentTheme ? prev : currentTheme);
36
36
  const topToast = currentToasts.find(t => !t.isExiting);
37
- isBottomRef.current.value = currentTheme.position === "bottom";
38
- isDismissibleRef.current.value = topToast?.options?.dismissible ?? currentTheme.dismissible;
37
+ isBottomMutable.set(currentTheme.position === "bottom");
38
+ isDismissibleMutable.set(topToast?.options?.dismissible ?? currentTheme.dismissible);
39
39
  });
40
40
  }
41
41
  });
42
42
  return unsubscribe;
43
- }, []);
43
+ }, [isBottomMutable, isDismissibleMutable]);
44
44
  const toastsWithIndex = useMemo(() => {
45
45
  const indices = new Map();
46
46
  let visualIndex = 0;
@@ -59,9 +59,9 @@ export const useToastState = () => {
59
59
  toastsWithIndex,
60
60
  isBottom,
61
61
  isTopDismissible,
62
- topToastRef,
63
- isBottomRef,
64
- isDismissibleRef
62
+ topToastMutable,
63
+ isBottomMutable,
64
+ isDismissibleMutable
65
65
  };
66
66
  };
67
67
  //# sourceMappingURL=use-toast-state.js.map
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { TextStyle, ViewStyle } from "react-native";
3
+ import type { SharedValue } from "react-native-reanimated";
3
4
  export type ToastType = "success" | "error" | "info" | "loading";
4
5
  export type ToastPosition = "top" | "bottom";
5
6
  export interface ToastTypeColors {
@@ -35,7 +36,11 @@ export interface ToastTheme {
35
36
  position: ToastPosition;
36
37
  /** Extra offset from safe area edge (in addition to safe area insets) */
37
38
  offset: number;
38
- /** Enable right-to-left layout (reverses icon/text order) */
39
+ /**
40
+ * Enable right-to-left layout at the code level (reverses icon/text order and text alignment).
41
+ * Only needed when you handle RTL in JavaScript — native RTL (e.g. via `I18nManager.forceRTL`)
42
+ * already flips the entire layout automatically, so this option is unnecessary in that case.
43
+ */
39
44
  rtl: boolean;
40
45
  /** Whether to show multiple toasts stacked (default: true). When false, only one toast shows at a time. */
41
46
  stacking: boolean;
@@ -121,15 +126,9 @@ export interface PromiseResult<T> {
121
126
  }
122
127
  export interface TopToastRef {
123
128
  slot: {
124
- progress: {
125
- value: number;
126
- };
127
- translationY: {
128
- value: number;
129
- };
130
- stackIndex: {
131
- value: number;
132
- };
129
+ progress: SharedValue<number>;
130
+ translationY: SharedValue<number>;
131
+ stackIndex: SharedValue<number>;
133
132
  };
134
133
  dismiss: () => void;
135
134
  }
@@ -9,8 +9,8 @@ export declare const useToastState: () => {
9
9
  }[];
10
10
  isBottom: boolean;
11
11
  isTopDismissible: boolean;
12
- topToastRef: import("react").RefObject<import("react-native-reanimated/lib/typescript/commonTypes").Mutable<TopToastRef | null>>;
13
- isBottomRef: import("react").RefObject<import("react-native-reanimated/lib/typescript/commonTypes").Mutable<boolean>>;
14
- isDismissibleRef: import("react").RefObject<import("react-native-reanimated/lib/typescript/commonTypes").Mutable<boolean>>;
12
+ topToastMutable: import("react-native-reanimated/lib/typescript/commonTypes").Mutable<TopToastRef | null>;
13
+ isBottomMutable: import("react-native-reanimated/lib/typescript/commonTypes").Mutable<boolean>;
14
+ isDismissibleMutable: import("react-native-reanimated/lib/typescript/commonTypes").Mutable<boolean>;
15
15
  };
16
16
  //# sourceMappingURL=use-toast-state.d.ts.map
package/package.json CHANGED
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "react-native-bread",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "A lightweight toast library for React Native with premium feeling animations and complex gesture support",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
7
7
  "types": "lib/typescript/index.d.ts",
8
8
  "react-native": "lib/module/index.js",
9
- "files": ["lib", "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", "!**/*.map"],
9
+ "files": [
10
+ "lib",
11
+ "src",
12
+ "!**/__tests__",
13
+ "!**/__fixtures__",
14
+ "!**/__mocks__",
15
+ "!**/*.map",
16
+ "README.md"
17
+ ],
10
18
  "sideEffects": false,
11
19
  "repository": {
12
20
  "type": "git",
@@ -31,21 +39,55 @@
31
39
  "reanimated"
32
40
  ],
33
41
  "scripts": {
42
+ "prepack": "cp ../README.md ./README.md",
43
+ "postpack": "rm ./README.md",
34
44
  "build": "bob build",
35
45
  "typecheck": "tsc --noEmit",
36
46
  "clean": "rm -rf lib",
37
- "prepare": "bob build"
47
+ "prepare": "bob build",
48
+ "release": "release-it"
49
+ },
50
+ "publishConfig": {
51
+ "registry": "https://registry.npmjs.org/"
52
+ },
53
+ "release-it": {
54
+ "git": {
55
+ "commitMessage": "chore: release v${version}",
56
+ "tagName": "v${version}"
57
+ },
58
+ "npm": {
59
+ "publish": true,
60
+ "skipChecks": true,
61
+ "publishArgs": [
62
+ "--provenance --access public"
63
+ ]
64
+ },
65
+ "github": {
66
+ "release": true
67
+ },
68
+ "hooks": {
69
+ "before:init": "bun run build"
70
+ },
71
+ "plugins": {
72
+ "@release-it/conventional-changelog": {
73
+ "preset": "conventionalcommits",
74
+ "infile": "../CHANGELOG.md"
75
+ }
76
+ }
38
77
  },
39
78
  "devDependencies": {
79
+ "@release-it/conventional-changelog": "^10.0.5",
80
+ "@types/react": "^19.1.0",
40
81
  "react": "19.1.0",
41
82
  "react-native": "0.81.5",
42
83
  "react-native-builder-bob": "^0.35.2",
43
84
  "react-native-gesture-handler": "~2.28.0",
44
85
  "react-native-reanimated": "~4.2.1",
45
- "react-native-safe-area-context": "~5.4.0",
86
+ "react-native-safe-area-context": "~5.6.0",
46
87
  "react-native-screens": "~4.16.0",
47
88
  "react-native-svg": "15.12.1",
48
89
  "react-native-worklets": "0.7.2",
90
+ "release-it": "^19.2.4",
49
91
  "terser": "^5.44.1",
50
92
  "typescript": "~5.9.2"
51
93
  },
@@ -0,0 +1,23 @@
1
+ import { Easing } from "react-native-reanimated";
2
+
3
+ export const ICON_SIZE = 28;
4
+ export const POOL_SIZE = 5;
5
+
6
+ export const ENTRY_DURATION = 400;
7
+ export const EXIT_DURATION = 350;
8
+ export const STACK_TRANSITION_DURATION = 300;
9
+ export const SPRING_BACK_DURATION = 650;
10
+ export const ICON_ANIMATION_DURATION = 350;
11
+
12
+ export const ENTRY_OFFSET = 80;
13
+ export const EXIT_OFFSET = 100;
14
+ export const SWIPE_EXIT_OFFSET = 200;
15
+ export const MAX_DRAG_CLAMP = 180;
16
+ export const MAX_DRAG_RESISTANCE = 60;
17
+ export const DISMISS_THRESHOLD = 40;
18
+ export const DISMISS_VELOCITY_THRESHOLD = 300;
19
+
20
+ export const STACK_OFFSET_PER_ITEM = 10;
21
+ export const STACK_SCALE_PER_ITEM = 0.05;
22
+
23
+ export const EASING = Easing.bezier(0.25, 0.1, 0.25, 1.0);
@@ -0,0 +1,10 @@
1
+ import Svg, { Path, type SvgProps } from "react-native-svg";
2
+
3
+ export const CloseIcon = (props: SvgProps) => (
4
+ <Svg viewBox="0 0 24 24" width={24} height={24} fill="none" {...props}>
5
+ <Path
6
+ fill={props.fill ?? "#8993A4"}
7
+ d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"
8
+ />
9
+ </Svg>
10
+ );
@@ -0,0 +1,16 @@
1
+ import Svg, { Path, type SvgProps } from "react-native-svg";
2
+
3
+ export const GreenCheck = (props: SvgProps) => (
4
+ <Svg viewBox="0 0 30 31" width={30} height={31} fill="none" {...props}>
5
+ <Path
6
+ fill={props.fill ?? "#28B770"}
7
+ fillRule="evenodd"
8
+ d="m19.866 13.152-5.772 5.773a.933.933 0 0 1-1.326 0L9.88 16.039a.938.938 0 0 1 1.325-1.327l2.225 2.224 5.109-5.11a.938.938 0 1 1 1.326 1.326Zm.28-9.652H9.602C5.654 3.5 3 6.276 3 10.409v9.935c0 4.131 2.654 6.906 6.602 6.906h10.543c3.95 0 6.605-2.775 6.605-6.906v-9.935c0-4.133-2.654-6.909-6.604-6.909Z"
9
+ clipRule="evenodd"
10
+ />
11
+ <Path
12
+ fill="#fff"
13
+ d="m19.866 13.152-5.772 5.773a.933.933 0 0 1-1.326 0L9.88 16.039a.938.938 0 0 1 1.325-1.327l2.225 2.224 5.109-5.11a.938.938 0 1 1 1.326 1.326Z"
14
+ />
15
+ </Svg>
16
+ );
@@ -0,0 +1,12 @@
1
+ import Svg, { Path, type SvgProps } from "react-native-svg";
2
+
3
+ export const InfoIcon = (props: SvgProps) => (
4
+ <Svg viewBox="0 0 24 24" width={24} height={24} fill="none" {...props}>
5
+ <Path
6
+ fill={props.fill ?? "#EDBE43"}
7
+ fillRule="evenodd"
8
+ d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2Zm1 15h-2v-6h2v6Zm0-8h-2V7h2v2Z"
9
+ clipRule="evenodd"
10
+ />
11
+ </Svg>
12
+ );