react-native-bread 0.5.2 → 0.6.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 +27 -11
- package/lib/commonjs/constants.js +25 -1
- package/lib/commonjs/icons/CloseIcon.js +22 -1
- package/lib/commonjs/icons/GreenCheck.js +27 -1
- package/lib/commonjs/icons/InfoIcon.js +24 -1
- package/lib/commonjs/icons/RedX.js +27 -1
- package/lib/commonjs/icons/index.js +34 -1
- package/lib/commonjs/index.js +65 -1
- package/lib/commonjs/pool.js +53 -1
- package/lib/commonjs/toast-api.js +127 -1
- package/lib/commonjs/toast-icons.js +80 -1
- package/lib/commonjs/toast-provider.js +109 -1
- package/lib/commonjs/toast-store.js +252 -1
- package/lib/commonjs/toast.js +351 -1
- package/lib/commonjs/types.js +6 -1
- package/lib/commonjs/use-toast-state.js +72 -1
- package/lib/module/constants.js +21 -1
- package/lib/module/icons/CloseIcon.js +16 -1
- package/lib/module/icons/GreenCheck.js +21 -1
- package/lib/module/icons/InfoIcon.js +18 -1
- package/lib/module/icons/RedX.js +21 -1
- package/lib/module/icons/index.js +7 -1
- package/lib/module/index.js +14 -1
- package/lib/module/pool.js +47 -1
- package/lib/module/toast-api.js +123 -1
- package/lib/module/toast-icons.js +74 -1
- package/lib/module/toast-provider.js +104 -1
- package/lib/module/toast-store.js +248 -1
- package/lib/module/toast.js +345 -1
- package/lib/module/types.js +4 -1
- package/lib/module/use-toast-state.js +67 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/toast-provider.d.ts +28 -0
- package/package.json +7 -3
package/lib/commonjs/toast.js
CHANGED
|
@@ -1 +1,351 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ToastContainer = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeGestureHandler = require("react-native-gesture-handler");
|
|
10
|
+
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
|
|
11
|
+
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
|
|
12
|
+
var _reactNativeWorklets = require("react-native-worklets");
|
|
13
|
+
var _constants = require("./constants.js");
|
|
14
|
+
var _index = require("./icons/index.js");
|
|
15
|
+
var _pool = require("./pool.js");
|
|
16
|
+
var _toastIcons = require("./toast-icons.js");
|
|
17
|
+
var _toastStore = require("./toast-store.js");
|
|
18
|
+
var _useToastState = require("./use-toast-state.js");
|
|
19
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
20
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
21
|
+
const ToastContainer = () => {
|
|
22
|
+
const {
|
|
23
|
+
top,
|
|
24
|
+
bottom
|
|
25
|
+
} = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
26
|
+
const {
|
|
27
|
+
visibleToasts,
|
|
28
|
+
theme,
|
|
29
|
+
toastsWithIndex,
|
|
30
|
+
isBottom,
|
|
31
|
+
topToastRef,
|
|
32
|
+
isBottomRef,
|
|
33
|
+
isDismissibleRef
|
|
34
|
+
} = (0, _useToastState.useToastState)();
|
|
35
|
+
const shouldDismiss = (0, _reactNativeReanimated.useSharedValue)(false);
|
|
36
|
+
const panGesture = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().onStart(() => {
|
|
37
|
+
"worklet";
|
|
38
|
+
|
|
39
|
+
shouldDismiss.set(false);
|
|
40
|
+
}).onUpdate(event => {
|
|
41
|
+
"worklet";
|
|
42
|
+
|
|
43
|
+
if (!isDismissibleRef.current.value) return;
|
|
44
|
+
const ref = topToastRef.current.value;
|
|
45
|
+
if (!ref) return;
|
|
46
|
+
const {
|
|
47
|
+
slot
|
|
48
|
+
} = ref;
|
|
49
|
+
const bottom = isBottomRef.current.value;
|
|
50
|
+
const rawY = event.translationY;
|
|
51
|
+
const dismissDrag = bottom ? rawY : -rawY;
|
|
52
|
+
const resistDrag = bottom ? -rawY : rawY;
|
|
53
|
+
if (dismissDrag > 0) {
|
|
54
|
+
const clampedY = bottom ? Math.min(rawY, _constants.MAX_DRAG_CLAMP) : Math.max(rawY, -_constants.MAX_DRAG_CLAMP);
|
|
55
|
+
slot.translationY.value = clampedY;
|
|
56
|
+
const shouldTriggerDismiss = dismissDrag > _constants.DISMISS_THRESHOLD || (bottom ? event.velocityY > _constants.DISMISS_VELOCITY_THRESHOLD : event.velocityY < -_constants.DISMISS_VELOCITY_THRESHOLD);
|
|
57
|
+
shouldDismiss.set(shouldTriggerDismiss);
|
|
58
|
+
} else {
|
|
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;
|
|
62
|
+
}
|
|
63
|
+
}).onEnd(() => {
|
|
64
|
+
"worklet";
|
|
65
|
+
|
|
66
|
+
if (!isDismissibleRef.current.value) return;
|
|
67
|
+
const ref = topToastRef.current.value;
|
|
68
|
+
if (!ref) return;
|
|
69
|
+
const {
|
|
70
|
+
slot
|
|
71
|
+
} = ref;
|
|
72
|
+
const bottom = isBottomRef.current.value;
|
|
73
|
+
if (shouldDismiss.value) {
|
|
74
|
+
slot.progress.value = (0, _reactNativeReanimated.withTiming)(0, {
|
|
75
|
+
duration: _constants.EXIT_DURATION,
|
|
76
|
+
easing: _constants.EASING
|
|
77
|
+
});
|
|
78
|
+
const exitOffset = bottom ? _constants.SWIPE_EXIT_OFFSET : -_constants.SWIPE_EXIT_OFFSET;
|
|
79
|
+
slot.translationY.value = (0, _reactNativeReanimated.withTiming)(slot.translationY.value + exitOffset, {
|
|
80
|
+
duration: _constants.EXIT_DURATION,
|
|
81
|
+
easing: _constants.EASING
|
|
82
|
+
});
|
|
83
|
+
(0, _reactNativeWorklets.scheduleOnRN)(ref.dismiss);
|
|
84
|
+
} else {
|
|
85
|
+
slot.translationY.value = (0, _reactNativeReanimated.withTiming)(0, {
|
|
86
|
+
duration: _constants.SPRING_BACK_DURATION,
|
|
87
|
+
easing: _constants.EASING
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}), [shouldDismiss, isDismissibleRef, topToastRef, isBottomRef]);
|
|
91
|
+
const registerTopToast = (0, _react.useCallback)(values => {
|
|
92
|
+
topToastRef.current.value = values;
|
|
93
|
+
}, [topToastRef]);
|
|
94
|
+
if (visibleToasts.length === 0) return null;
|
|
95
|
+
const inset = isBottom ? bottom : top;
|
|
96
|
+
const positionStyle = isBottom ? {
|
|
97
|
+
bottom: inset + theme.offset + 2
|
|
98
|
+
} : {
|
|
99
|
+
top: inset + theme.offset + 2
|
|
100
|
+
};
|
|
101
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
|
|
102
|
+
gesture: panGesture,
|
|
103
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
104
|
+
style: [styles.container, positionStyle],
|
|
105
|
+
pointerEvents: "box-none",
|
|
106
|
+
children: toastsWithIndex.map(({
|
|
107
|
+
toast,
|
|
108
|
+
index
|
|
109
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(MemoizedToastItem, {
|
|
110
|
+
toast: toast,
|
|
111
|
+
index: index,
|
|
112
|
+
theme: theme,
|
|
113
|
+
position: theme.position,
|
|
114
|
+
isTopToast: index === 0,
|
|
115
|
+
registerTopToast: registerTopToast
|
|
116
|
+
}, toast.id))
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
exports.ToastContainer = ToastContainer;
|
|
121
|
+
const ToastItem = ({
|
|
122
|
+
toast,
|
|
123
|
+
index,
|
|
124
|
+
theme,
|
|
125
|
+
position,
|
|
126
|
+
isTopToast,
|
|
127
|
+
registerTopToast
|
|
128
|
+
}) => {
|
|
129
|
+
const [slotIdx] = (0, _react.useState)(() => (0, _pool.getSlotIndex)(toast.id));
|
|
130
|
+
const slot = _pool.animationPool[slotIdx];
|
|
131
|
+
const tracker = _pool.slotTrackers[slotIdx];
|
|
132
|
+
const isBottom = position === "bottom";
|
|
133
|
+
const entryFromY = isBottom ? _constants.ENTRY_OFFSET : -_constants.ENTRY_OFFSET;
|
|
134
|
+
const exitToY = isBottom ? _constants.EXIT_OFFSET : -_constants.EXIT_OFFSET;
|
|
135
|
+
const [wasLoading, setWasLoading] = (0, _react.useState)(toast.type === "loading");
|
|
136
|
+
const [showIcon, setShowIcon] = (0, _react.useState)(false);
|
|
137
|
+
|
|
138
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: mount-only effect
|
|
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, {
|
|
144
|
+
duration: _constants.ENTRY_DURATION,
|
|
145
|
+
easing: _constants.EASING
|
|
146
|
+
});
|
|
147
|
+
const iconTimeout = setTimeout(() => setShowIcon(true), 50);
|
|
148
|
+
return () => {
|
|
149
|
+
clearTimeout(iconTimeout);
|
|
150
|
+
(0, _pool.releaseSlot)(toast.id);
|
|
151
|
+
};
|
|
152
|
+
}, []);
|
|
153
|
+
const dismissToast = (0, _react.useCallback)(() => {
|
|
154
|
+
_toastStore.toastStore.hide(toast.id);
|
|
155
|
+
}, [toast.id]);
|
|
156
|
+
(0, _react.useEffect)(() => {
|
|
157
|
+
let loadingTimeout = null;
|
|
158
|
+
if (toast.isExiting && !tracker.wasExiting) {
|
|
159
|
+
tracker.wasExiting = true;
|
|
160
|
+
slot.progress.value = (0, _reactNativeReanimated.withTiming)(0, {
|
|
161
|
+
duration: _constants.EXIT_DURATION,
|
|
162
|
+
easing: _constants.EASING
|
|
163
|
+
});
|
|
164
|
+
slot.translationY.value = (0, _reactNativeReanimated.withTiming)(exitToY, {
|
|
165
|
+
duration: _constants.EXIT_DURATION,
|
|
166
|
+
easing: _constants.EASING
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (tracker.initialized && index !== tracker.prevIndex) {
|
|
170
|
+
slot.stackIndex.value = (0, _reactNativeReanimated.withTiming)(index, {
|
|
171
|
+
duration: _constants.STACK_TRANSITION_DURATION,
|
|
172
|
+
easing: _constants.EASING
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
tracker.prevIndex = index;
|
|
176
|
+
tracker.initialized = true;
|
|
177
|
+
if (toast.type === "loading") {
|
|
178
|
+
setWasLoading(true);
|
|
179
|
+
} else if (wasLoading) {
|
|
180
|
+
loadingTimeout = setTimeout(() => setWasLoading(false), _constants.ICON_ANIMATION_DURATION + 50);
|
|
181
|
+
}
|
|
182
|
+
if (isTopToast) {
|
|
183
|
+
registerTopToast({
|
|
184
|
+
slot: slot,
|
|
185
|
+
dismiss: dismissToast
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return () => {
|
|
189
|
+
if (loadingTimeout) clearTimeout(loadingTimeout);
|
|
190
|
+
if (isTopToast) registerTopToast(null);
|
|
191
|
+
};
|
|
192
|
+
}, [toast.isExiting, index, slot, tracker, exitToY, toast.type, wasLoading, isTopToast, registerTopToast, dismissToast]);
|
|
193
|
+
const shouldAnimateIcon = wasLoading && toast.type !== "loading";
|
|
194
|
+
const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
|
|
195
|
+
const baseTranslateY = (0, _reactNativeReanimated.interpolate)(slot.progress.value, [0, 1], [entryFromY, 0]);
|
|
196
|
+
const stackOffsetY = isBottom ? slot.stackIndex.value * _constants.STACK_OFFSET_PER_ITEM : slot.stackIndex.value * -_constants.STACK_OFFSET_PER_ITEM;
|
|
197
|
+
const stackScale = 1 - slot.stackIndex.value * _constants.STACK_SCALE_PER_ITEM;
|
|
198
|
+
const finalTranslateY = baseTranslateY + slot.translationY.value + stackOffsetY;
|
|
199
|
+
const progressOpacity = (0, _reactNativeReanimated.interpolate)(slot.progress.value, [0, 1], [0, 1]);
|
|
200
|
+
const dismissDirection = isBottom ? slot.translationY.value : -slot.translationY.value;
|
|
201
|
+
const dragOpacity = dismissDirection > 0 ? (0, _reactNativeReanimated.interpolate)(dismissDirection, [0, 130], [1, 0], "clamp") : 1;
|
|
202
|
+
const opacity = progressOpacity * dragOpacity;
|
|
203
|
+
const dragScale = (0, _reactNativeReanimated.interpolate)(Math.abs(slot.translationY.value), [0, 50], [1, 0.98], "clamp");
|
|
204
|
+
const scale = stackScale * dragScale;
|
|
205
|
+
return {
|
|
206
|
+
transform: [{
|
|
207
|
+
translateY: finalTranslateY
|
|
208
|
+
}, {
|
|
209
|
+
scale
|
|
210
|
+
}],
|
|
211
|
+
opacity,
|
|
212
|
+
zIndex: 1000 - Math.round(slot.stackIndex.value)
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
const {
|
|
216
|
+
options
|
|
217
|
+
} = toast;
|
|
218
|
+
const colors = theme.colors[toast.type];
|
|
219
|
+
if (options?.customContent !== undefined) {
|
|
220
|
+
const content = options.customContent;
|
|
221
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
|
|
222
|
+
style: [styles.toast, styles.customContentToast, isBottom ? styles.toastBottom : styles.toastTop, {
|
|
223
|
+
backgroundColor: colors.background
|
|
224
|
+
}, theme.toastStyle, options.style, animatedStyle],
|
|
225
|
+
children: typeof content === "function" ? content({
|
|
226
|
+
id: toast.id,
|
|
227
|
+
dismiss: dismissToast,
|
|
228
|
+
type: toast.type,
|
|
229
|
+
isExiting: !!toast.isExiting
|
|
230
|
+
}) : content
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const shouldShowCloseButton = toast.type !== "loading" && (options?.showCloseButton ?? theme.showCloseButton);
|
|
234
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.View, {
|
|
235
|
+
style: [styles.toast, isBottom ? styles.toastBottom : styles.toastTop, {
|
|
236
|
+
backgroundColor: colors.background
|
|
237
|
+
}, theme.rtl && styles.rtl, theme.toastStyle, options?.style, animatedStyle],
|
|
238
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
239
|
+
style: styles.iconContainer,
|
|
240
|
+
children: showIcon && (shouldAnimateIcon ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_toastIcons.AnimatedIcon, {
|
|
241
|
+
type: toast.type,
|
|
242
|
+
color: colors.accent,
|
|
243
|
+
custom: options?.icon,
|
|
244
|
+
config: theme.icons[toast.type]
|
|
245
|
+
}, toast.type) : (0, _toastIcons.resolveIcon)(toast.type, colors.accent, options?.icon, theme.icons[toast.type]))
|
|
246
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
247
|
+
style: styles.textContainer,
|
|
248
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
249
|
+
maxFontSizeMultiplier: 1.35,
|
|
250
|
+
allowFontScaling: false,
|
|
251
|
+
style: [styles.title, {
|
|
252
|
+
color: colors.accent
|
|
253
|
+
}, theme.rtl && {
|
|
254
|
+
textAlign: "right"
|
|
255
|
+
}, theme.titleStyle, options?.titleStyle],
|
|
256
|
+
children: toast.title
|
|
257
|
+
}), toast.description && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
258
|
+
allowFontScaling: false,
|
|
259
|
+
maxFontSizeMultiplier: 1.35,
|
|
260
|
+
style: [styles.description, theme.rtl && {
|
|
261
|
+
textAlign: "right"
|
|
262
|
+
}, theme.descriptionStyle, options?.descriptionStyle],
|
|
263
|
+
children: toast.description
|
|
264
|
+
})]
|
|
265
|
+
}), shouldShowCloseButton && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
266
|
+
style: styles.closeButton,
|
|
267
|
+
onPress: dismissToast,
|
|
268
|
+
hitSlop: 12,
|
|
269
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.CloseIcon, {
|
|
270
|
+
width: 20,
|
|
271
|
+
height: 20
|
|
272
|
+
})
|
|
273
|
+
})]
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
const MemoizedToastItem = /*#__PURE__*/(0, _react.memo)(ToastItem, (prev, next) => {
|
|
277
|
+
return prev.toast.id === next.toast.id && prev.toast.type === next.toast.type && prev.toast.title === next.toast.title && prev.toast.description === next.toast.description && prev.toast.isExiting === next.toast.isExiting && prev.index === next.index && prev.position === next.position && prev.theme === next.theme && prev.isTopToast === next.isTopToast;
|
|
278
|
+
});
|
|
279
|
+
const styles = _reactNative.StyleSheet.create({
|
|
280
|
+
container: {
|
|
281
|
+
position: "absolute",
|
|
282
|
+
left: 16,
|
|
283
|
+
right: 16,
|
|
284
|
+
zIndex: 1000
|
|
285
|
+
},
|
|
286
|
+
toast: {
|
|
287
|
+
flexDirection: "row",
|
|
288
|
+
alignItems: "center",
|
|
289
|
+
gap: 12,
|
|
290
|
+
minHeight: 36,
|
|
291
|
+
borderRadius: 20,
|
|
292
|
+
borderCurve: "continuous",
|
|
293
|
+
position: "absolute",
|
|
294
|
+
left: 0,
|
|
295
|
+
right: 0,
|
|
296
|
+
paddingHorizontal: 12,
|
|
297
|
+
paddingVertical: 10,
|
|
298
|
+
shadowColor: "#000",
|
|
299
|
+
shadowOffset: {
|
|
300
|
+
width: 0,
|
|
301
|
+
height: 8
|
|
302
|
+
},
|
|
303
|
+
shadowOpacity: 0.05,
|
|
304
|
+
shadowRadius: 24,
|
|
305
|
+
elevation: 8
|
|
306
|
+
},
|
|
307
|
+
customContentToast: {
|
|
308
|
+
padding: 0,
|
|
309
|
+
paddingHorizontal: 0,
|
|
310
|
+
paddingVertical: 0,
|
|
311
|
+
overflow: "hidden"
|
|
312
|
+
},
|
|
313
|
+
rtl: {
|
|
314
|
+
flexDirection: "row-reverse"
|
|
315
|
+
},
|
|
316
|
+
toastTop: {
|
|
317
|
+
top: 0
|
|
318
|
+
},
|
|
319
|
+
toastBottom: {
|
|
320
|
+
bottom: 0
|
|
321
|
+
},
|
|
322
|
+
iconContainer: {
|
|
323
|
+
width: 48,
|
|
324
|
+
height: 48,
|
|
325
|
+
alignItems: "center",
|
|
326
|
+
justifyContent: "center",
|
|
327
|
+
marginLeft: 8
|
|
328
|
+
},
|
|
329
|
+
textContainer: {
|
|
330
|
+
flex: 1,
|
|
331
|
+
gap: 1,
|
|
332
|
+
justifyContent: "center"
|
|
333
|
+
},
|
|
334
|
+
title: {
|
|
335
|
+
fontSize: 14,
|
|
336
|
+
fontWeight: "700",
|
|
337
|
+
lineHeight: 20
|
|
338
|
+
},
|
|
339
|
+
description: {
|
|
340
|
+
color: "#6B7280",
|
|
341
|
+
fontSize: 12,
|
|
342
|
+
fontWeight: "500",
|
|
343
|
+
lineHeight: 16
|
|
344
|
+
},
|
|
345
|
+
closeButton: {
|
|
346
|
+
padding: 4,
|
|
347
|
+
alignItems: "center",
|
|
348
|
+
justifyContent: "center"
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
//# sourceMappingURL=toast.js.map
|
package/lib/commonjs/types.js
CHANGED
|
@@ -1 +1,72 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useToastState = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNativeReanimated = require("react-native-reanimated");
|
|
9
|
+
var _toastStore = require("./toast-store.js");
|
|
10
|
+
const useToastState = () => {
|
|
11
|
+
const [visibleToasts, setVisibleToasts] = (0, _react.useState)([]);
|
|
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));
|
|
16
|
+
const isBottom = theme.position === "bottom";
|
|
17
|
+
const topToast = visibleToasts.find(t => !t.isExiting);
|
|
18
|
+
const isTopDismissible = topToast?.options?.dismissible ?? theme.dismissible;
|
|
19
|
+
(0, _react.useEffect)(() => {
|
|
20
|
+
const initialToasts = _toastStore.toastStore.getState().visibleToasts;
|
|
21
|
+
const initialTheme = _toastStore.toastStore.getTheme();
|
|
22
|
+
setVisibleToasts(initialToasts);
|
|
23
|
+
const initialTopToast = initialToasts.find(t => !t.isExiting);
|
|
24
|
+
isBottomRef.current.value = initialTheme.position === "bottom";
|
|
25
|
+
isDismissibleRef.current.value = initialTopToast?.options?.dismissible ?? initialTheme.dismissible;
|
|
26
|
+
let pendingToasts = null;
|
|
27
|
+
let rafId = null;
|
|
28
|
+
const unsubscribe = _toastStore.toastStore.subscribe(state => {
|
|
29
|
+
pendingToasts = state.visibleToasts;
|
|
30
|
+
if (rafId === null) {
|
|
31
|
+
rafId = requestAnimationFrame(() => {
|
|
32
|
+
const currentToasts = pendingToasts ?? _toastStore.toastStore.getState().visibleToasts;
|
|
33
|
+
const currentTheme = _toastStore.toastStore.getTheme();
|
|
34
|
+
if (pendingToasts) {
|
|
35
|
+
setVisibleToasts(pendingToasts);
|
|
36
|
+
pendingToasts = null;
|
|
37
|
+
}
|
|
38
|
+
rafId = null;
|
|
39
|
+
setTheme(prev => prev === currentTheme ? prev : currentTheme);
|
|
40
|
+
const topToast = currentToasts.find(t => !t.isExiting);
|
|
41
|
+
isBottomRef.current.value = currentTheme.position === "bottom";
|
|
42
|
+
isDismissibleRef.current.value = topToast?.options?.dismissible ?? currentTheme.dismissible;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return unsubscribe;
|
|
47
|
+
}, []);
|
|
48
|
+
const toastsWithIndex = (0, _react.useMemo)(() => {
|
|
49
|
+
const indices = new Map();
|
|
50
|
+
let visualIndex = 0;
|
|
51
|
+
for (const t of visibleToasts) {
|
|
52
|
+
indices.set(t.id, t.isExiting ? -1 : visualIndex);
|
|
53
|
+
if (!t.isExiting) visualIndex++;
|
|
54
|
+
}
|
|
55
|
+
return [...visibleToasts].reverse().map(t => ({
|
|
56
|
+
toast: t,
|
|
57
|
+
index: indices.get(t.id) ?? 0
|
|
58
|
+
}));
|
|
59
|
+
}, [visibleToasts]);
|
|
60
|
+
return {
|
|
61
|
+
visibleToasts,
|
|
62
|
+
theme,
|
|
63
|
+
toastsWithIndex,
|
|
64
|
+
isBottom,
|
|
65
|
+
isTopDismissible,
|
|
66
|
+
topToastRef,
|
|
67
|
+
isBottomRef,
|
|
68
|
+
isDismissibleRef
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.useToastState = useToastState;
|
|
72
|
+
//# sourceMappingURL=use-toast-state.js.map
|
package/lib/module/constants.js
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Easing } from "react-native-reanimated";
|
|
4
|
+
export const ICON_SIZE = 28;
|
|
5
|
+
export const POOL_SIZE = 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
|
+
export const ENTRY_OFFSET = 80;
|
|
12
|
+
export const EXIT_OFFSET = 100;
|
|
13
|
+
export const SWIPE_EXIT_OFFSET = 200;
|
|
14
|
+
export const MAX_DRAG_CLAMP = 180;
|
|
15
|
+
export const MAX_DRAG_RESISTANCE = 60;
|
|
16
|
+
export const DISMISS_THRESHOLD = 40;
|
|
17
|
+
export const DISMISS_VELOCITY_THRESHOLD = 300;
|
|
18
|
+
export const STACK_OFFSET_PER_ITEM = 10;
|
|
19
|
+
export const STACK_SCALE_PER_ITEM = 0.05;
|
|
20
|
+
export const EASING = Easing.bezier(0.25, 0.1, 0.25, 1.0);
|
|
21
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1,16 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import Svg, { Path } from "react-native-svg";
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
export const CloseIcon = props => /*#__PURE__*/_jsx(Svg, {
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: 24,
|
|
8
|
+
height: 24,
|
|
9
|
+
fill: "none",
|
|
10
|
+
...props,
|
|
11
|
+
children: /*#__PURE__*/_jsx(Path, {
|
|
12
|
+
fill: props.fill ?? "#8993A4",
|
|
13
|
+
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"
|
|
14
|
+
})
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=CloseIcon.js.map
|
|
@@ -1 +1,21 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import Svg, { Path } from "react-native-svg";
|
|
4
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
export const GreenCheck = props => /*#__PURE__*/_jsxs(Svg, {
|
|
6
|
+
viewBox: "0 0 30 31",
|
|
7
|
+
width: 30,
|
|
8
|
+
height: 31,
|
|
9
|
+
fill: "none",
|
|
10
|
+
...props,
|
|
11
|
+
children: [/*#__PURE__*/_jsx(Path, {
|
|
12
|
+
fill: props.fill ?? "#28B770",
|
|
13
|
+
fillRule: "evenodd",
|
|
14
|
+
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",
|
|
15
|
+
clipRule: "evenodd"
|
|
16
|
+
}), /*#__PURE__*/_jsx(Path, {
|
|
17
|
+
fill: "#fff",
|
|
18
|
+
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"
|
|
19
|
+
})]
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=GreenCheck.js.map
|
|
@@ -1 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import Svg, { Path } from "react-native-svg";
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
export const InfoIcon = props => /*#__PURE__*/_jsx(Svg, {
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: 24,
|
|
8
|
+
height: 24,
|
|
9
|
+
fill: "none",
|
|
10
|
+
...props,
|
|
11
|
+
children: /*#__PURE__*/_jsx(Path, {
|
|
12
|
+
fill: props.fill ?? "#EDBE43",
|
|
13
|
+
fillRule: "evenodd",
|
|
14
|
+
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",
|
|
15
|
+
clipRule: "evenodd"
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=InfoIcon.js.map
|
package/lib/module/icons/RedX.js
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import Svg, { Path } from "react-native-svg";
|
|
4
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
export const RedX = props => /*#__PURE__*/_jsxs(Svg, {
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: 24,
|
|
8
|
+
height: 24,
|
|
9
|
+
fill: "none",
|
|
10
|
+
...props,
|
|
11
|
+
children: [/*#__PURE__*/_jsx(Path, {
|
|
12
|
+
fill: props.fill ?? "#F05964",
|
|
13
|
+
fillRule: "evenodd",
|
|
14
|
+
d: "M15.58 15.572a.935.935 0 0 1-1.326 0l-2.258-2.258-2.251 2.252a.938.938 0 0 1-1.326-1.325l2.251-2.252-2.252-2.254A.936.936 0 1 1 9.742 8.41l2.253 2.252 2.252-2.25a.939.939 0 0 1 1.325 1.325l-2.25 2.252 2.257 2.257a.938.938 0 0 1 0 1.326ZM17.271.126H6.727C2.777.125.125 2.9.125 7.032v9.936c0 4.13 2.652 6.907 6.603 6.907H17.27c3.95 0 6.605-2.776 6.605-6.907V7.032c0-4.132-2.654-6.907-6.604-6.907Z",
|
|
15
|
+
clipRule: "evenodd"
|
|
16
|
+
}), /*#__PURE__*/_jsx(Path, {
|
|
17
|
+
fill: "#fff",
|
|
18
|
+
d: "M15.58 15.572a.935.935 0 0 1-1.326 0l-2.258-2.258-2.251 2.252a.938.938 0 0 1-1.326-1.325l2.251-2.252-2.252-2.254A.936.936 0 1 1 9.742 8.41l2.253 2.252 2.252-2.25a.939.939 0 0 1 1.325 1.325l-2.25 2.252 2.257 2.257a.938.938 0 0 1 0 1.326Z"
|
|
19
|
+
})]
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=RedX.js.map
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export { CloseIcon } from "./CloseIcon.js";
|
|
4
|
+
export { GreenCheck } from "./GreenCheck.js";
|
|
5
|
+
export { InfoIcon } from "./InfoIcon.js";
|
|
6
|
+
export { RedX } from "./RedX.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Main exports
|
|
4
|
+
|
|
5
|
+
// Icons (for customization)
|
|
6
|
+
export { CloseIcon, GreenCheck, InfoIcon, RedX } from "./icons/index.js";
|
|
7
|
+
export { ToastContainer } from "./toast.js";
|
|
8
|
+
export { toast } from "./toast-api.js";
|
|
9
|
+
export { BreadLoaf, ToastPortal } from "./toast-provider.js";
|
|
10
|
+
|
|
11
|
+
// Store (for advanced usage)
|
|
12
|
+
export { toastStore } from "./toast-store.js";
|
|
13
|
+
// Types
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
package/lib/module/pool.js
CHANGED
|
@@ -1 +1,47 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { makeMutable } from "react-native-reanimated";
|
|
4
|
+
import { POOL_SIZE } from "./constants.js";
|
|
5
|
+
export const animationPool = Array.from({
|
|
6
|
+
length: POOL_SIZE
|
|
7
|
+
}, () => ({
|
|
8
|
+
progress: makeMutable(0),
|
|
9
|
+
translationY: makeMutable(0),
|
|
10
|
+
stackIndex: makeMutable(0)
|
|
11
|
+
}));
|
|
12
|
+
export const slotTrackers = Array.from({
|
|
13
|
+
length: POOL_SIZE
|
|
14
|
+
}, () => ({
|
|
15
|
+
wasExiting: false,
|
|
16
|
+
prevIndex: 0,
|
|
17
|
+
initialized: false
|
|
18
|
+
}));
|
|
19
|
+
const slotAssignments = new Map();
|
|
20
|
+
const usedSlots = new Set();
|
|
21
|
+
export const getSlotIndex = toastId => {
|
|
22
|
+
if (slotAssignments.has(toastId)) {
|
|
23
|
+
return slotAssignments.get(toastId) ?? 0;
|
|
24
|
+
}
|
|
25
|
+
for (let i = 0; i < POOL_SIZE; i++) {
|
|
26
|
+
if (!usedSlots.has(i)) {
|
|
27
|
+
slotAssignments.set(toastId, i);
|
|
28
|
+
usedSlots.add(i);
|
|
29
|
+
slotTrackers[i].initialized = false;
|
|
30
|
+
slotTrackers[i].wasExiting = false;
|
|
31
|
+
slotTrackers[i].prevIndex = 0;
|
|
32
|
+
return i;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
};
|
|
37
|
+
export const releaseSlot = toastId => {
|
|
38
|
+
const idx = slotAssignments.get(toastId);
|
|
39
|
+
if (idx !== undefined) {
|
|
40
|
+
usedSlots.delete(idx);
|
|
41
|
+
slotAssignments.delete(toastId);
|
|
42
|
+
slotTrackers[idx].initialized = false;
|
|
43
|
+
slotTrackers[idx].wasExiting = false;
|
|
44
|
+
slotTrackers[idx].prevIndex = 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=pool.js.map
|