@metamask/design-system-react-native 0.38.0 → 0.39.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/CHANGELOG.md +19 -1
- package/dist/components/BottomSheetDialog/BottomSheetDialog.cjs +1 -1
- package/dist/components/BottomSheetDialog/BottomSheetDialog.cjs.map +1 -1
- package/dist/components/BottomSheetDialog/BottomSheetDialog.mjs +1 -1
- package/dist/components/BottomSheetDialog/BottomSheetDialog.mjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.cjs +5 -5
- package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.mjs +5 -5
- package/dist/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/components/Toast/Toast.constants.cjs +19 -1
- package/dist/components/Toast/Toast.constants.cjs.map +1 -1
- package/dist/components/Toast/Toast.constants.d.cts +18 -0
- package/dist/components/Toast/Toast.constants.d.cts.map +1 -1
- package/dist/components/Toast/Toast.constants.d.mts +18 -0
- package/dist/components/Toast/Toast.constants.d.mts.map +1 -1
- package/dist/components/Toast/Toast.constants.mjs +18 -0
- package/dist/components/Toast/Toast.constants.mjs.map +1 -1
- package/dist/components/Toast/Toaster.cjs +172 -15
- package/dist/components/Toast/Toaster.cjs.map +1 -1
- package/dist/components/Toast/Toaster.d.cts.map +1 -1
- package/dist/components/Toast/Toaster.d.mts.map +1 -1
- package/dist/components/Toast/Toaster.mjs +174 -17
- package/dist/components/Toast/Toaster.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -28,6 +28,7 @@ exports.toast = exports.Toaster = void 0;
|
|
|
28
28
|
const design_system_twrnc_preset_1 = require("@metamask/design-system-twrnc-preset");
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
30
|
const react_native_1 = require("react-native");
|
|
31
|
+
const react_native_gesture_handler_1 = require("react-native-gesture-handler");
|
|
31
32
|
const react_native_reanimated_1 = __importStar(require("react-native-reanimated"));
|
|
32
33
|
const react_native_safe_area_context_1 = require("react-native-safe-area-context");
|
|
33
34
|
const react_native_worklets_1 = require("react-native-worklets");
|
|
@@ -49,10 +50,23 @@ const ToasterComponent = (0, react_1.forwardRef)(({ twClassName, ...props }, ref
|
|
|
49
50
|
const tw = (0, design_system_twrnc_preset_1.useTailwind)();
|
|
50
51
|
const [toastOptions, setToastOptions] = (0, react_1.useState)(undefined);
|
|
51
52
|
const replacementTimerRef = (0, react_1.useRef)(null);
|
|
53
|
+
const autoDismissTimeoutRef = (0, react_1.useRef)(null);
|
|
54
|
+
const animationStartedRef = (0, react_1.useRef)(false);
|
|
55
|
+
const visibleAtRef = (0, react_1.useRef)(null);
|
|
56
|
+
const hasNoTimeoutRef = (0, react_1.useRef)(false);
|
|
57
|
+
// Invalidates queued spring-back resumes after replace/dismiss. A completed
|
|
58
|
+
// spring cannot be cancelled, so scheduleOnRN(resume) can still run later.
|
|
59
|
+
const toastGenerationRef = (0, react_1.useRef)(0);
|
|
52
60
|
const { top: topInset } = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
|
|
53
61
|
const toastHeight = (0, react_native_reanimated_1.useSharedValue)(screenHeight);
|
|
62
|
+
const hiddenTranslateY = (0, react_native_reanimated_1.useSharedValue)(-screenHeight);
|
|
63
|
+
const visibleTranslateY = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
64
|
+
const gestureStartY = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
54
65
|
const translateYProgress = (0, react_native_reanimated_1.useSharedValue)(-screenHeight);
|
|
66
|
+
const isDismissing = (0, react_native_reanimated_1.useSharedValue)(false);
|
|
67
|
+
const toastGeneration = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
55
68
|
const topOffset = toastOptions?.topOffset ?? 0;
|
|
69
|
+
hasNoTimeoutRef.current = Boolean(toastOptions?.hasNoTimeout);
|
|
56
70
|
const animatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
|
|
57
71
|
transform: [{ translateY: translateYProgress.value + topOffset }],
|
|
58
72
|
}));
|
|
@@ -61,16 +75,78 @@ const ToasterComponent = (0, react_1.forwardRef)(({ twClassName, ...props }, ref
|
|
|
61
75
|
animatedStyle,
|
|
62
76
|
], [tw, animatedStyle]);
|
|
63
77
|
const innerRef = (0, react_1.useRef)(null);
|
|
64
|
-
const
|
|
78
|
+
const clearScheduledAutoDismiss = () => {
|
|
79
|
+
if (autoDismissTimeoutRef.current !== null) {
|
|
80
|
+
clearTimeout(autoDismissTimeoutRef.current);
|
|
81
|
+
autoDismissTimeoutRef.current = null;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const bumpToastGeneration = () => {
|
|
85
|
+
toastGenerationRef.current += 1;
|
|
86
|
+
toastGeneration.value = toastGenerationRef.current;
|
|
87
|
+
};
|
|
88
|
+
const resetState = () => {
|
|
89
|
+
animationStartedRef.current = false;
|
|
90
|
+
visibleAtRef.current = null;
|
|
91
|
+
isDismissing.value = false;
|
|
92
|
+
clearScheduledAutoDismiss();
|
|
93
|
+
setToastOptions(undefined);
|
|
94
|
+
};
|
|
95
|
+
const startDismissAnimation = () => {
|
|
96
|
+
bumpToastGeneration();
|
|
97
|
+
clearScheduledAutoDismiss();
|
|
98
|
+
isDismissing.value = true;
|
|
99
|
+
visibleAtRef.current = null;
|
|
100
|
+
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(hiddenTranslateY.value, Toast_constants_1.TOAST_SPRING_CONFIG, (finished) => {
|
|
101
|
+
if (finished) {
|
|
102
|
+
(0, react_native_worklets_1.scheduleOnRN)(resetState);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
const scheduleAutoDismiss = (delayMs) => {
|
|
107
|
+
clearScheduledAutoDismiss();
|
|
108
|
+
autoDismissTimeoutRef.current = setTimeout(() => {
|
|
109
|
+
autoDismissTimeoutRef.current = null;
|
|
110
|
+
startDismissAnimation();
|
|
111
|
+
}, delayMs);
|
|
112
|
+
};
|
|
113
|
+
const beginAutoDismiss = () => {
|
|
114
|
+
visibleAtRef.current = Date.now();
|
|
115
|
+
scheduleAutoDismiss(Toast_constants_1.TOAST_VISIBILITY_DURATION);
|
|
116
|
+
};
|
|
117
|
+
const resumeAutoDismissAfterSwipe = () => {
|
|
118
|
+
if (hasNoTimeoutRef.current || isDismissing.value) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Entrance was interrupted before auto-dismiss started — start a full timer.
|
|
122
|
+
if (visibleAtRef.current === null) {
|
|
123
|
+
beginAutoDismiss();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const elapsed = Date.now() - visibleAtRef.current;
|
|
127
|
+
if (elapsed >= Toast_constants_1.TOAST_VISIBILITY_DURATION) {
|
|
128
|
+
startDismissAnimation();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
scheduleAutoDismiss(Toast_constants_1.TOAST_VISIBILITY_DURATION - elapsed);
|
|
132
|
+
};
|
|
65
133
|
const showToast = (options) => {
|
|
134
|
+
bumpToastGeneration();
|
|
66
135
|
let timeoutDuration = 0;
|
|
67
136
|
const normalizedOptions = {
|
|
68
137
|
hasNoTimeout: false,
|
|
69
138
|
...options,
|
|
70
139
|
};
|
|
71
140
|
if (toastOptions) {
|
|
141
|
+
// Always clear any pending auto-dismiss from the previous toast, including
|
|
142
|
+
// when the replacement is persistent (hasNoTimeout). Otherwise the old
|
|
143
|
+
// timer can fire and dismiss the new toast.
|
|
144
|
+
clearScheduledAutoDismiss();
|
|
72
145
|
(0, react_native_reanimated_1.cancelAnimation)(translateYProgress);
|
|
73
146
|
timeoutDuration = 100;
|
|
147
|
+
animationStartedRef.current = false;
|
|
148
|
+
visibleAtRef.current = null;
|
|
149
|
+
isDismissing.value = false;
|
|
74
150
|
setToastOptions(undefined);
|
|
75
151
|
}
|
|
76
152
|
if (replacementTimerRef.current !== null) {
|
|
@@ -86,10 +162,83 @@ const ToasterComponent = (0, react_1.forwardRef)(({ twClassName, ...props }, ref
|
|
|
86
162
|
clearTimeout(replacementTimerRef.current);
|
|
87
163
|
replacementTimerRef.current = null;
|
|
88
164
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
165
|
+
startDismissAnimation();
|
|
166
|
+
};
|
|
167
|
+
const closeToastRef = (0, react_1.useRef)(closeToast);
|
|
168
|
+
const resumeAutoDismissAfterSwipeRef = (0, react_1.useRef)(resumeAutoDismissAfterSwipe);
|
|
169
|
+
const clearScheduledAutoDismissRef = (0, react_1.useRef)(clearScheduledAutoDismiss);
|
|
170
|
+
closeToastRef.current = closeToast;
|
|
171
|
+
resumeAutoDismissAfterSwipeRef.current = resumeAutoDismissAfterSwipe;
|
|
172
|
+
clearScheduledAutoDismissRef.current = clearScheduledAutoDismiss;
|
|
173
|
+
const dismissToastFromSwipe = () => {
|
|
174
|
+
closeToastRef.current();
|
|
175
|
+
};
|
|
176
|
+
const resumeAutoDismissFromSwipe = (generation) => {
|
|
177
|
+
// Ignore resumes from a toast that was replaced or dismissed after the
|
|
178
|
+
// spring-back started (completed springs cannot be cancelled).
|
|
179
|
+
if (generation !== toastGenerationRef.current) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
resumeAutoDismissAfterSwipeRef.current();
|
|
183
|
+
};
|
|
184
|
+
const clearScheduledAutoDismissFromSwipe = () => {
|
|
185
|
+
clearScheduledAutoDismissRef.current();
|
|
92
186
|
};
|
|
187
|
+
const swipeGesture = (0, react_1.useMemo)(() =>
|
|
188
|
+
// These gesture callbacks need explicit 'worklet' directives because this
|
|
189
|
+
// package ships a pre-built dist compiled by ts-bridge (tsc), which emits the
|
|
190
|
+
// gesture chain as a namespaced call (react_native_gesture_handler_1.Gesture).
|
|
191
|
+
// The consumer's Reanimated/Worklets Babel plugin does run over dist, but its
|
|
192
|
+
// gesture auto-detection doesn't recognize that compiled namespaced form.
|
|
193
|
+
react_native_gesture_handler_1.Gesture.Pan()
|
|
194
|
+
.activeOffsetY(Toast_constants_1.TOAST_SWIPE_ACTIVE_OFFSET_Y)
|
|
195
|
+
.failOffsetX([-Toast_constants_1.TOAST_SWIPE_FAIL_OFFSET_X, Toast_constants_1.TOAST_SWIPE_FAIL_OFFSET_X])
|
|
196
|
+
.onStart(() => {
|
|
197
|
+
'worklet';
|
|
198
|
+
// Don't interrupt an in-progress dismiss animation.
|
|
199
|
+
if (isDismissing.value) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
(0, react_native_worklets_1.scheduleOnRN)(clearScheduledAutoDismissFromSwipe);
|
|
203
|
+
(0, react_native_reanimated_1.cancelAnimation)(translateYProgress);
|
|
204
|
+
gestureStartY.value = translateYProgress.value;
|
|
205
|
+
})
|
|
206
|
+
.onUpdate((event) => {
|
|
207
|
+
'worklet';
|
|
208
|
+
if (isDismissing.value) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const nextTranslateY = gestureStartY.value + event.translationY;
|
|
212
|
+
// Toast sits at the top; only allow dragging upward (more negative).
|
|
213
|
+
translateYProgress.value = Math.min(nextTranslateY, visibleTranslateY.value);
|
|
214
|
+
})
|
|
215
|
+
.onEnd((event) => {
|
|
216
|
+
'worklet';
|
|
217
|
+
if (isDismissing.value) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const { translationY, velocityY } = event;
|
|
221
|
+
const dismissDistance = Math.max(toastHeight.value * Toast_constants_1.TOAST_DISMISS_DISTANCE_THRESHOLD, 24);
|
|
222
|
+
const hasReachedDismissOffset = translationY <= -dismissDistance;
|
|
223
|
+
const hasReachedSwipeThreshold = Math.abs(velocityY) > Toast_constants_1.TOAST_DISMISS_VELOCITY_THRESHOLD;
|
|
224
|
+
const isQuickDismissing = velocityY < 0;
|
|
225
|
+
const shouldDismiss = hasReachedDismissOffset ||
|
|
226
|
+
(hasReachedSwipeThreshold && isQuickDismissing);
|
|
227
|
+
if (shouldDismiss) {
|
|
228
|
+
(0, react_native_worklets_1.scheduleOnRN)(dismissToastFromSwipe);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const generationAtSpringStart = toastGeneration.value;
|
|
232
|
+
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(visibleTranslateY.value, Toast_constants_1.TOAST_SPRING_CONFIG, (finished) => {
|
|
233
|
+
// A new pan cancels this spring via cancelAnimation; only resume
|
|
234
|
+
// auto-dismiss when the spring-back completed naturally.
|
|
235
|
+
if (finished) {
|
|
236
|
+
(0, react_native_worklets_1.scheduleOnRN)(resumeAutoDismissFromSwipe, generationAtSpringStart);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}),
|
|
240
|
+
// Shared values and swipe JS wrappers are stable for the component lifetime.
|
|
241
|
+
[]);
|
|
93
242
|
innerRef.current = {
|
|
94
243
|
closeToast,
|
|
95
244
|
showToast,
|
|
@@ -114,30 +263,38 @@ const ToasterComponent = (0, react_1.forwardRef)(({ twClassName, ...props }, ref
|
|
|
114
263
|
.join(' ');
|
|
115
264
|
const onAnimatedViewLayout = (e) => {
|
|
116
265
|
const { height } = e.nativeEvent.layout;
|
|
117
|
-
const
|
|
118
|
-
const
|
|
266
|
+
const nextHiddenTranslateY = getHiddenTranslateY(height, topOffset);
|
|
267
|
+
const nextVisibleTranslateY = topInset + Toast_constants_1.TOAST_TOP_PADDING;
|
|
268
|
+
hiddenTranslateY.value = nextHiddenTranslateY;
|
|
269
|
+
visibleTranslateY.value = nextVisibleTranslateY;
|
|
119
270
|
toastHeight.value = height;
|
|
120
|
-
|
|
271
|
+
if (animationStartedRef.current) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
animationStartedRef.current = true;
|
|
275
|
+
translateYProgress.value = nextHiddenTranslateY;
|
|
121
276
|
if (toastOptions.hasNoTimeout) {
|
|
122
|
-
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(
|
|
277
|
+
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(nextVisibleTranslateY, Toast_constants_1.TOAST_SPRING_CONFIG);
|
|
123
278
|
}
|
|
124
279
|
else {
|
|
125
|
-
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(
|
|
126
|
-
|
|
127
|
-
(0, react_native_worklets_1.scheduleOnRN)(
|
|
128
|
-
}
|
|
280
|
+
translateYProgress.value = (0, react_native_reanimated_1.withSpring)(nextVisibleTranslateY, Toast_constants_1.TOAST_SPRING_CONFIG, (finished) => {
|
|
281
|
+
if (finished) {
|
|
282
|
+
(0, react_native_worklets_1.scheduleOnRN)(beginAutoDismiss);
|
|
283
|
+
}
|
|
129
284
|
});
|
|
130
285
|
}
|
|
131
286
|
};
|
|
132
|
-
return (<
|
|
133
|
-
|
|
287
|
+
return (<react_native_gesture_handler_1.GestureDetector gesture={swipeGesture}>
|
|
288
|
+
<react_native_reanimated_1.default.View onLayout={onAnimatedViewLayout} style={baseStyle} {...props}>
|
|
289
|
+
{actionButtonLabel && actionButtonOnPress ? (<Toast_1.Toast {...toastProps} actionButtonLabel={actionButtonLabel} actionButtonOnPress={actionButtonOnPress} onClose={() => {
|
|
134
290
|
closeToast();
|
|
135
291
|
toastOnClose?.();
|
|
136
292
|
}} twClassName={toastTwClassNames}/>) : (<Toast_1.Toast {...restToastProps} onClose={() => {
|
|
137
293
|
closeToast();
|
|
138
294
|
toastOnClose?.();
|
|
139
295
|
}} twClassName={toastTwClassNames}/>)}
|
|
140
|
-
|
|
296
|
+
</react_native_reanimated_1.default.View>
|
|
297
|
+
</react_native_gesture_handler_1.GestureDetector>);
|
|
141
298
|
});
|
|
142
299
|
ToasterComponent.displayName = 'Toaster';
|
|
143
300
|
exports.Toaster = ToasterComponent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.cjs","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"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","sourcesContent":["// Third party dependencies.\nimport { useTailwind } from '@metamask/design-system-twrnc-preset';\nimport React, {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { RefObject } from 'react';\nimport { Dimensions } from 'react-native';\nimport type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';\nimport Animated, {\n cancelAnimation,\n useAnimatedStyle,\n useSharedValue,\n withDelay,\n withSpring,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { scheduleOnRN } from 'react-native-worklets';\n\n// Internal dependencies.\nimport { Toast } from './Toast';\nimport {\n TOAST_SPRING_CONFIG,\n TOAST_TOP_PADDING,\n TOAST_VISIBILITY_DURATION,\n} from './Toast.constants';\nimport type {\n ToastOptions,\n ToastProps,\n ToasterProps,\n ToasterRef,\n} from './Toast.types';\n\nconst screenHeight = Dimensions.get('window').height;\n\nlet registeredRef: RefObject<ToasterRef | null> | null = null;\n\nconst assertRegisteredRef = (method: 'dismiss' | 'toast'): ToasterRef => {\n if (!registeredRef?.current) {\n const invocation = method === 'toast' ? 'toast()' : `toast.${method}()`;\n throw new Error(\n `${invocation} called before <Toaster /> mounted. Render <Toaster /> once at the root of your app.`,\n );\n }\n return registeredRef.current;\n};\n\nconst getToastProps = ({\n hasNoTimeout: _hasNoTimeout,\n onClose: _onClose,\n topOffset: _topOffset,\n twClassName: _twClassName,\n ...toastProps\n}: ToastOptions): Omit<ToastProps, 'twClassName'> => toastProps;\n\nconst getHiddenTranslateY = (height: number, offset: number) =>\n -(height + offset);\n\nconst ToasterComponent = forwardRef<ToasterRef, ToasterProps>(\n ({ twClassName, ...props }, ref) => {\n const tw = useTailwind();\n const [toastOptions, setToastOptions] = useState<ToastOptions | undefined>(\n undefined,\n );\n const replacementTimerRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const { top: topInset } = useSafeAreaInsets();\n const toastHeight = useSharedValue(screenHeight);\n const translateYProgress = useSharedValue(-screenHeight);\n const topOffset = toastOptions?.topOffset ?? 0;\n const animatedStyle = useAnimatedStyle(() => ({\n transform: [{ translateY: translateYProgress.value + topOffset }],\n }));\n const baseStyle = useMemo(\n () =>\n [\n tw.style('absolute left-4 right-4 top-0'),\n animatedStyle,\n ] as StyleProp<ViewStyle>,\n [tw, animatedStyle],\n );\n const innerRef = useRef<ToasterRef | null>(null);\n\n const resetState = () => setToastOptions(undefined);\n\n const showToast = (options: ToastOptions) => {\n let timeoutDuration = 0;\n const normalizedOptions = {\n hasNoTimeout: false,\n ...options,\n };\n if (toastOptions) {\n cancelAnimation(translateYProgress);\n timeoutDuration = 100;\n setToastOptions(undefined);\n }\n if (replacementTimerRef.current !== null) {\n clearTimeout(replacementTimerRef.current);\n }\n replacementTimerRef.current = setTimeout(() => {\n replacementTimerRef.current = null;\n setToastOptions(normalizedOptions);\n }, timeoutDuration);\n };\n\n const closeToast = () => {\n if (replacementTimerRef.current !== null) {\n clearTimeout(replacementTimerRef.current);\n replacementTimerRef.current = null;\n }\n translateYProgress.value = withSpring(\n getHiddenTranslateY(toastHeight.value, topOffset),\n TOAST_SPRING_CONFIG,\n () => {\n scheduleOnRN(resetState);\n },\n );\n };\n\n innerRef.current = {\n closeToast,\n showToast,\n };\n\n useImperativeHandle(ref, () => innerRef.current as ToasterRef);\n\n useLayoutEffect(() => {\n registeredRef = innerRef;\n return () => {\n if (registeredRef === innerRef) {\n registeredRef = null;\n }\n };\n }, []);\n\n if (!toastOptions) {\n return null;\n }\n\n const { onClose: toastOnClose, twClassName: toastTwClassName } =\n toastOptions;\n const toastProps = getToastProps(toastOptions);\n const { actionButtonLabel, actionButtonOnPress, ...restToastProps } =\n toastProps;\n const toastTwClassNames = [twClassName, toastTwClassName]\n .filter(Boolean)\n .join(' ');\n\n const onAnimatedViewLayout = (e: LayoutChangeEvent) => {\n const { height } = e.nativeEvent.layout;\n const hiddenTranslateY = getHiddenTranslateY(height, topOffset);\n const visibleTranslateY = topInset + TOAST_TOP_PADDING;\n\n toastHeight.value = height;\n translateYProgress.value = hiddenTranslateY;\n\n if (toastOptions.hasNoTimeout) {\n translateYProgress.value = withSpring(\n visibleTranslateY,\n TOAST_SPRING_CONFIG,\n );\n } else {\n translateYProgress.value = withSpring(\n visibleTranslateY,\n TOAST_SPRING_CONFIG,\n () => {\n translateYProgress.value = withDelay(\n TOAST_VISIBILITY_DURATION,\n withSpring(hiddenTranslateY, TOAST_SPRING_CONFIG, () => {\n scheduleOnRN(resetState);\n }),\n );\n },\n );\n }\n };\n\n return (\n <Animated.View\n onLayout={onAnimatedViewLayout}\n style={baseStyle}\n {...props}\n >\n {actionButtonLabel && actionButtonOnPress ? (\n <Toast\n {...toastProps}\n actionButtonLabel={actionButtonLabel}\n actionButtonOnPress={actionButtonOnPress}\n onClose={() => {\n closeToast();\n toastOnClose?.();\n }}\n twClassName={toastTwClassNames}\n />\n ) : (\n <Toast\n {...restToastProps}\n onClose={() => {\n closeToast();\n toastOnClose?.();\n }}\n twClassName={toastTwClassNames}\n />\n )}\n </Animated.View>\n );\n },\n);\n\nToasterComponent.displayName = 'Toaster';\n\ntype ToastFunction = ((options: ToastOptions) => void) & {\n dismiss: () => void;\n};\n\nexport const Toaster = ToasterComponent;\n\nexport const toast = ((options: ToastOptions) => {\n assertRegisteredRef('toast').showToast(options);\n}) as ToastFunction;\n\ntoast.dismiss = () => {\n assertRegisteredRef('dismiss').closeToast();\n};\n"]}
|
|
1
|
+
{"version":3,"file":"Toaster.cjs","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"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","sourcesContent":["// Third party dependencies.\nimport { useTailwind } from '@metamask/design-system-twrnc-preset';\nimport React, {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { RefObject } from 'react';\nimport { Dimensions } from 'react-native';\nimport type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler';\nimport Animated, {\n cancelAnimation,\n useAnimatedStyle,\n useSharedValue,\n withSpring,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { scheduleOnRN } from 'react-native-worklets';\n\n// Internal dependencies.\nimport { Toast } from './Toast';\nimport {\n TOAST_DISMISS_DISTANCE_THRESHOLD,\n TOAST_DISMISS_VELOCITY_THRESHOLD,\n TOAST_SPRING_CONFIG,\n TOAST_SWIPE_ACTIVE_OFFSET_Y,\n TOAST_SWIPE_FAIL_OFFSET_X,\n TOAST_TOP_PADDING,\n TOAST_VISIBILITY_DURATION,\n} from './Toast.constants';\nimport type {\n ToastOptions,\n ToastProps,\n ToasterProps,\n ToasterRef,\n} from './Toast.types';\n\nconst screenHeight = Dimensions.get('window').height;\n\nlet registeredRef: RefObject<ToasterRef | null> | null = null;\n\nconst assertRegisteredRef = (method: 'dismiss' | 'toast'): ToasterRef => {\n if (!registeredRef?.current) {\n const invocation = method === 'toast' ? 'toast()' : `toast.${method}()`;\n throw new Error(\n `${invocation} called before <Toaster /> mounted. Render <Toaster /> once at the root of your app.`,\n );\n }\n return registeredRef.current;\n};\n\nconst getToastProps = ({\n hasNoTimeout: _hasNoTimeout,\n onClose: _onClose,\n topOffset: _topOffset,\n twClassName: _twClassName,\n ...toastProps\n}: ToastOptions): Omit<ToastProps, 'twClassName'> => toastProps;\n\nconst getHiddenTranslateY = (height: number, offset: number) =>\n -(height + offset);\n\nconst ToasterComponent = forwardRef<ToasterRef, ToasterProps>(\n ({ twClassName, ...props }, ref) => {\n const tw = useTailwind();\n const [toastOptions, setToastOptions] = useState<ToastOptions | undefined>(\n undefined,\n );\n const replacementTimerRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const autoDismissTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const animationStartedRef = useRef(false);\n const visibleAtRef = useRef<number | null>(null);\n const hasNoTimeoutRef = useRef(false);\n // Invalidates queued spring-back resumes after replace/dismiss. A completed\n // spring cannot be cancelled, so scheduleOnRN(resume) can still run later.\n const toastGenerationRef = useRef(0);\n const { top: topInset } = useSafeAreaInsets();\n const toastHeight = useSharedValue(screenHeight);\n const hiddenTranslateY = useSharedValue(-screenHeight);\n const visibleTranslateY = useSharedValue(0);\n const gestureStartY = useSharedValue(0);\n const translateYProgress = useSharedValue(-screenHeight);\n const isDismissing = useSharedValue(false);\n const toastGeneration = useSharedValue(0);\n const topOffset = toastOptions?.topOffset ?? 0;\n hasNoTimeoutRef.current = Boolean(toastOptions?.hasNoTimeout);\n const animatedStyle = useAnimatedStyle(() => ({\n transform: [{ translateY: translateYProgress.value + topOffset }],\n }));\n const baseStyle = useMemo(\n () =>\n [\n tw.style('absolute left-4 right-4 top-0'),\n animatedStyle,\n ] as StyleProp<ViewStyle>,\n [tw, animatedStyle],\n );\n const innerRef = useRef<ToasterRef | null>(null);\n\n const clearScheduledAutoDismiss = () => {\n if (autoDismissTimeoutRef.current !== null) {\n clearTimeout(autoDismissTimeoutRef.current);\n autoDismissTimeoutRef.current = null;\n }\n };\n\n const bumpToastGeneration = () => {\n toastGenerationRef.current += 1;\n toastGeneration.value = toastGenerationRef.current;\n };\n\n const resetState = () => {\n animationStartedRef.current = false;\n visibleAtRef.current = null;\n isDismissing.value = false;\n clearScheduledAutoDismiss();\n setToastOptions(undefined);\n };\n\n const startDismissAnimation = () => {\n bumpToastGeneration();\n clearScheduledAutoDismiss();\n isDismissing.value = true;\n visibleAtRef.current = null;\n translateYProgress.value = withSpring(\n hiddenTranslateY.value,\n TOAST_SPRING_CONFIG,\n (finished) => {\n if (finished) {\n scheduleOnRN(resetState);\n }\n },\n );\n };\n\n const scheduleAutoDismiss = (delayMs: number) => {\n clearScheduledAutoDismiss();\n autoDismissTimeoutRef.current = setTimeout(() => {\n autoDismissTimeoutRef.current = null;\n startDismissAnimation();\n }, delayMs);\n };\n\n const beginAutoDismiss = () => {\n visibleAtRef.current = Date.now();\n scheduleAutoDismiss(TOAST_VISIBILITY_DURATION);\n };\n\n const resumeAutoDismissAfterSwipe = () => {\n if (hasNoTimeoutRef.current || isDismissing.value) {\n return;\n }\n\n // Entrance was interrupted before auto-dismiss started — start a full timer.\n if (visibleAtRef.current === null) {\n beginAutoDismiss();\n return;\n }\n\n const elapsed = Date.now() - visibleAtRef.current;\n if (elapsed >= TOAST_VISIBILITY_DURATION) {\n startDismissAnimation();\n return;\n }\n\n scheduleAutoDismiss(TOAST_VISIBILITY_DURATION - elapsed);\n };\n\n const showToast = (options: ToastOptions) => {\n bumpToastGeneration();\n let timeoutDuration = 0;\n const normalizedOptions = {\n hasNoTimeout: false,\n ...options,\n };\n if (toastOptions) {\n // Always clear any pending auto-dismiss from the previous toast, including\n // when the replacement is persistent (hasNoTimeout). Otherwise the old\n // timer can fire and dismiss the new toast.\n clearScheduledAutoDismiss();\n cancelAnimation(translateYProgress);\n timeoutDuration = 100;\n animationStartedRef.current = false;\n visibleAtRef.current = null;\n isDismissing.value = false;\n setToastOptions(undefined);\n }\n if (replacementTimerRef.current !== null) {\n clearTimeout(replacementTimerRef.current);\n }\n replacementTimerRef.current = setTimeout(() => {\n replacementTimerRef.current = null;\n setToastOptions(normalizedOptions);\n }, timeoutDuration);\n };\n\n const closeToast = () => {\n if (replacementTimerRef.current !== null) {\n clearTimeout(replacementTimerRef.current);\n replacementTimerRef.current = null;\n }\n startDismissAnimation();\n };\n\n const closeToastRef = useRef(closeToast);\n const resumeAutoDismissAfterSwipeRef = useRef(resumeAutoDismissAfterSwipe);\n const clearScheduledAutoDismissRef = useRef(clearScheduledAutoDismiss);\n closeToastRef.current = closeToast;\n resumeAutoDismissAfterSwipeRef.current = resumeAutoDismissAfterSwipe;\n clearScheduledAutoDismissRef.current = clearScheduledAutoDismiss;\n\n const dismissToastFromSwipe = () => {\n closeToastRef.current();\n };\n\n const resumeAutoDismissFromSwipe = (generation: number) => {\n // Ignore resumes from a toast that was replaced or dismissed after the\n // spring-back started (completed springs cannot be cancelled).\n if (generation !== toastGenerationRef.current) {\n return;\n }\n resumeAutoDismissAfterSwipeRef.current();\n };\n\n const clearScheduledAutoDismissFromSwipe = () => {\n clearScheduledAutoDismissRef.current();\n };\n\n const swipeGesture = useMemo(\n () =>\n // These gesture callbacks need explicit 'worklet' directives because this\n // package ships a pre-built dist compiled by ts-bridge (tsc), which emits the\n // gesture chain as a namespaced call (react_native_gesture_handler_1.Gesture).\n // The consumer's Reanimated/Worklets Babel plugin does run over dist, but its\n // gesture auto-detection doesn't recognize that compiled namespaced form.\n Gesture.Pan()\n .activeOffsetY(TOAST_SWIPE_ACTIVE_OFFSET_Y)\n .failOffsetX([-TOAST_SWIPE_FAIL_OFFSET_X, TOAST_SWIPE_FAIL_OFFSET_X])\n .onStart(() => {\n 'worklet';\n\n // Don't interrupt an in-progress dismiss animation.\n if (isDismissing.value) {\n return;\n }\n scheduleOnRN(clearScheduledAutoDismissFromSwipe);\n cancelAnimation(translateYProgress);\n gestureStartY.value = translateYProgress.value;\n })\n .onUpdate((event) => {\n 'worklet';\n\n if (isDismissing.value) {\n return;\n }\n const nextTranslateY = gestureStartY.value + event.translationY;\n // Toast sits at the top; only allow dragging upward (more negative).\n translateYProgress.value = Math.min(\n nextTranslateY,\n visibleTranslateY.value,\n );\n })\n .onEnd((event) => {\n 'worklet';\n\n if (isDismissing.value) {\n return;\n }\n const { translationY, velocityY } = event;\n const dismissDistance = Math.max(\n toastHeight.value * TOAST_DISMISS_DISTANCE_THRESHOLD,\n 24,\n );\n const hasReachedDismissOffset = translationY <= -dismissDistance;\n const hasReachedSwipeThreshold =\n Math.abs(velocityY) > TOAST_DISMISS_VELOCITY_THRESHOLD;\n const isQuickDismissing = velocityY < 0;\n\n const shouldDismiss =\n hasReachedDismissOffset ||\n (hasReachedSwipeThreshold && isQuickDismissing);\n\n if (shouldDismiss) {\n scheduleOnRN(dismissToastFromSwipe);\n return;\n }\n\n const generationAtSpringStart = toastGeneration.value;\n translateYProgress.value = withSpring(\n visibleTranslateY.value,\n TOAST_SPRING_CONFIG,\n (finished) => {\n // A new pan cancels this spring via cancelAnimation; only resume\n // auto-dismiss when the spring-back completed naturally.\n if (finished) {\n scheduleOnRN(\n resumeAutoDismissFromSwipe,\n generationAtSpringStart,\n );\n }\n },\n );\n }),\n // Shared values and swipe JS wrappers are stable for the component lifetime.\n [],\n );\n\n innerRef.current = {\n closeToast,\n showToast,\n };\n\n useImperativeHandle(ref, () => innerRef.current as ToasterRef);\n\n useLayoutEffect(() => {\n registeredRef = innerRef;\n return () => {\n if (registeredRef === innerRef) {\n registeredRef = null;\n }\n };\n }, []);\n\n if (!toastOptions) {\n return null;\n }\n\n const { onClose: toastOnClose, twClassName: toastTwClassName } =\n toastOptions;\n const toastProps = getToastProps(toastOptions);\n const { actionButtonLabel, actionButtonOnPress, ...restToastProps } =\n toastProps;\n const toastTwClassNames = [twClassName, toastTwClassName]\n .filter(Boolean)\n .join(' ');\n\n const onAnimatedViewLayout = (e: LayoutChangeEvent) => {\n const { height } = e.nativeEvent.layout;\n const nextHiddenTranslateY = getHiddenTranslateY(height, topOffset);\n const nextVisibleTranslateY = topInset + TOAST_TOP_PADDING;\n\n hiddenTranslateY.value = nextHiddenTranslateY;\n visibleTranslateY.value = nextVisibleTranslateY;\n toastHeight.value = height;\n\n if (animationStartedRef.current) {\n return;\n }\n\n animationStartedRef.current = true;\n translateYProgress.value = nextHiddenTranslateY;\n\n if (toastOptions.hasNoTimeout) {\n translateYProgress.value = withSpring(\n nextVisibleTranslateY,\n TOAST_SPRING_CONFIG,\n );\n } else {\n translateYProgress.value = withSpring(\n nextVisibleTranslateY,\n TOAST_SPRING_CONFIG,\n (finished) => {\n if (finished) {\n scheduleOnRN(beginAutoDismiss);\n }\n },\n );\n }\n };\n\n return (\n <GestureDetector gesture={swipeGesture}>\n <Animated.View\n onLayout={onAnimatedViewLayout}\n style={baseStyle}\n {...props}\n >\n {actionButtonLabel && actionButtonOnPress ? (\n <Toast\n {...toastProps}\n actionButtonLabel={actionButtonLabel}\n actionButtonOnPress={actionButtonOnPress}\n onClose={() => {\n closeToast();\n toastOnClose?.();\n }}\n twClassName={toastTwClassNames}\n />\n ) : (\n <Toast\n {...restToastProps}\n onClose={() => {\n closeToast();\n toastOnClose?.();\n }}\n twClassName={toastTwClassNames}\n />\n )}\n </Animated.View>\n </GestureDetector>\n );\n },\n);\n\nToasterComponent.displayName = 'Toaster';\n\ntype ToastFunction = ((options: ToastOptions) => void) & {\n dismiss: () => void;\n};\n\nexport const Toaster = ToasterComponent;\n\nexport const toast = ((options: ToastOptions) => {\n assertRegisteredRef('toast').showToast(options);\n}) as ToastFunction;\n\ntoast.dismiss = () => {\n assertRegisteredRef('dismiss').closeToast();\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.cts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,cAAc;
|
|
1
|
+
{"version":3,"file":"Toaster.d.cts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,cAAc;AAyBf,OAAO,KAAK,EACV,YAAY,EAGZ,UAAU,EACX,0BAAsB;AAuXvB,KAAK,aAAa,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG;IACvD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,OAAO;;sFAAmB,CAAC;AAExC,eAAO,MAAM,KAAK,eAEC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.mts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,cAAc;
|
|
1
|
+
{"version":3,"file":"Toaster.d.mts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,cAAc;AAyBf,OAAO,KAAK,EACV,YAAY,EAGZ,UAAU,EACX,0BAAsB;AAuXvB,KAAK,aAAa,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG;IACvD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,OAAO;;sFAAmB,CAAC;AAExC,eAAO,MAAM,KAAK,eAEC,CAAC"}
|
|
@@ -9,12 +9,13 @@ import { useTailwind } from "@metamask/design-system-twrnc-preset";
|
|
|
9
9
|
import $React, { forwardRef, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
10
10
|
const React = $importDefault($React);
|
|
11
11
|
import { Dimensions } from "react-native";
|
|
12
|
-
import
|
|
12
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
13
|
+
import Animated, { cancelAnimation, useAnimatedStyle, useSharedValue, withSpring } from "react-native-reanimated";
|
|
13
14
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
14
15
|
import { scheduleOnRN } from "react-native-worklets";
|
|
15
16
|
// Internal dependencies.
|
|
16
17
|
import { Toast } from "./Toast.mjs";
|
|
17
|
-
import { TOAST_SPRING_CONFIG, TOAST_TOP_PADDING, TOAST_VISIBILITY_DURATION } from "./Toast.constants.mjs";
|
|
18
|
+
import { TOAST_DISMISS_DISTANCE_THRESHOLD, TOAST_DISMISS_VELOCITY_THRESHOLD, TOAST_SPRING_CONFIG, TOAST_SWIPE_ACTIVE_OFFSET_Y, TOAST_SWIPE_FAIL_OFFSET_X, TOAST_TOP_PADDING, TOAST_VISIBILITY_DURATION } from "./Toast.constants.mjs";
|
|
18
19
|
const screenHeight = Dimensions.get('window').height;
|
|
19
20
|
let registeredRef = null;
|
|
20
21
|
const assertRegisteredRef = (method) => {
|
|
@@ -30,10 +31,23 @@ const ToasterComponent = forwardRef(({ twClassName, ...props }, ref) => {
|
|
|
30
31
|
const tw = useTailwind();
|
|
31
32
|
const [toastOptions, setToastOptions] = useState(undefined);
|
|
32
33
|
const replacementTimerRef = useRef(null);
|
|
34
|
+
const autoDismissTimeoutRef = useRef(null);
|
|
35
|
+
const animationStartedRef = useRef(false);
|
|
36
|
+
const visibleAtRef = useRef(null);
|
|
37
|
+
const hasNoTimeoutRef = useRef(false);
|
|
38
|
+
// Invalidates queued spring-back resumes after replace/dismiss. A completed
|
|
39
|
+
// spring cannot be cancelled, so scheduleOnRN(resume) can still run later.
|
|
40
|
+
const toastGenerationRef = useRef(0);
|
|
33
41
|
const { top: topInset } = useSafeAreaInsets();
|
|
34
42
|
const toastHeight = useSharedValue(screenHeight);
|
|
43
|
+
const hiddenTranslateY = useSharedValue(-screenHeight);
|
|
44
|
+
const visibleTranslateY = useSharedValue(0);
|
|
45
|
+
const gestureStartY = useSharedValue(0);
|
|
35
46
|
const translateYProgress = useSharedValue(-screenHeight);
|
|
47
|
+
const isDismissing = useSharedValue(false);
|
|
48
|
+
const toastGeneration = useSharedValue(0);
|
|
36
49
|
const topOffset = toastOptions?.topOffset ?? 0;
|
|
50
|
+
hasNoTimeoutRef.current = Boolean(toastOptions?.hasNoTimeout);
|
|
37
51
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
38
52
|
transform: [{ translateY: translateYProgress.value + topOffset }],
|
|
39
53
|
}));
|
|
@@ -42,16 +56,78 @@ const ToasterComponent = forwardRef(({ twClassName, ...props }, ref) => {
|
|
|
42
56
|
animatedStyle,
|
|
43
57
|
], [tw, animatedStyle]);
|
|
44
58
|
const innerRef = useRef(null);
|
|
45
|
-
const
|
|
59
|
+
const clearScheduledAutoDismiss = () => {
|
|
60
|
+
if (autoDismissTimeoutRef.current !== null) {
|
|
61
|
+
clearTimeout(autoDismissTimeoutRef.current);
|
|
62
|
+
autoDismissTimeoutRef.current = null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const bumpToastGeneration = () => {
|
|
66
|
+
toastGenerationRef.current += 1;
|
|
67
|
+
toastGeneration.value = toastGenerationRef.current;
|
|
68
|
+
};
|
|
69
|
+
const resetState = () => {
|
|
70
|
+
animationStartedRef.current = false;
|
|
71
|
+
visibleAtRef.current = null;
|
|
72
|
+
isDismissing.value = false;
|
|
73
|
+
clearScheduledAutoDismiss();
|
|
74
|
+
setToastOptions(undefined);
|
|
75
|
+
};
|
|
76
|
+
const startDismissAnimation = () => {
|
|
77
|
+
bumpToastGeneration();
|
|
78
|
+
clearScheduledAutoDismiss();
|
|
79
|
+
isDismissing.value = true;
|
|
80
|
+
visibleAtRef.current = null;
|
|
81
|
+
translateYProgress.value = withSpring(hiddenTranslateY.value, TOAST_SPRING_CONFIG, (finished) => {
|
|
82
|
+
if (finished) {
|
|
83
|
+
scheduleOnRN(resetState);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const scheduleAutoDismiss = (delayMs) => {
|
|
88
|
+
clearScheduledAutoDismiss();
|
|
89
|
+
autoDismissTimeoutRef.current = setTimeout(() => {
|
|
90
|
+
autoDismissTimeoutRef.current = null;
|
|
91
|
+
startDismissAnimation();
|
|
92
|
+
}, delayMs);
|
|
93
|
+
};
|
|
94
|
+
const beginAutoDismiss = () => {
|
|
95
|
+
visibleAtRef.current = Date.now();
|
|
96
|
+
scheduleAutoDismiss(TOAST_VISIBILITY_DURATION);
|
|
97
|
+
};
|
|
98
|
+
const resumeAutoDismissAfterSwipe = () => {
|
|
99
|
+
if (hasNoTimeoutRef.current || isDismissing.value) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Entrance was interrupted before auto-dismiss started — start a full timer.
|
|
103
|
+
if (visibleAtRef.current === null) {
|
|
104
|
+
beginAutoDismiss();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const elapsed = Date.now() - visibleAtRef.current;
|
|
108
|
+
if (elapsed >= TOAST_VISIBILITY_DURATION) {
|
|
109
|
+
startDismissAnimation();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
scheduleAutoDismiss(TOAST_VISIBILITY_DURATION - elapsed);
|
|
113
|
+
};
|
|
46
114
|
const showToast = (options) => {
|
|
115
|
+
bumpToastGeneration();
|
|
47
116
|
let timeoutDuration = 0;
|
|
48
117
|
const normalizedOptions = {
|
|
49
118
|
hasNoTimeout: false,
|
|
50
119
|
...options,
|
|
51
120
|
};
|
|
52
121
|
if (toastOptions) {
|
|
122
|
+
// Always clear any pending auto-dismiss from the previous toast, including
|
|
123
|
+
// when the replacement is persistent (hasNoTimeout). Otherwise the old
|
|
124
|
+
// timer can fire and dismiss the new toast.
|
|
125
|
+
clearScheduledAutoDismiss();
|
|
53
126
|
cancelAnimation(translateYProgress);
|
|
54
127
|
timeoutDuration = 100;
|
|
128
|
+
animationStartedRef.current = false;
|
|
129
|
+
visibleAtRef.current = null;
|
|
130
|
+
isDismissing.value = false;
|
|
55
131
|
setToastOptions(undefined);
|
|
56
132
|
}
|
|
57
133
|
if (replacementTimerRef.current !== null) {
|
|
@@ -67,10 +143,83 @@ const ToasterComponent = forwardRef(({ twClassName, ...props }, ref) => {
|
|
|
67
143
|
clearTimeout(replacementTimerRef.current);
|
|
68
144
|
replacementTimerRef.current = null;
|
|
69
145
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
146
|
+
startDismissAnimation();
|
|
147
|
+
};
|
|
148
|
+
const closeToastRef = useRef(closeToast);
|
|
149
|
+
const resumeAutoDismissAfterSwipeRef = useRef(resumeAutoDismissAfterSwipe);
|
|
150
|
+
const clearScheduledAutoDismissRef = useRef(clearScheduledAutoDismiss);
|
|
151
|
+
closeToastRef.current = closeToast;
|
|
152
|
+
resumeAutoDismissAfterSwipeRef.current = resumeAutoDismissAfterSwipe;
|
|
153
|
+
clearScheduledAutoDismissRef.current = clearScheduledAutoDismiss;
|
|
154
|
+
const dismissToastFromSwipe = () => {
|
|
155
|
+
closeToastRef.current();
|
|
156
|
+
};
|
|
157
|
+
const resumeAutoDismissFromSwipe = (generation) => {
|
|
158
|
+
// Ignore resumes from a toast that was replaced or dismissed after the
|
|
159
|
+
// spring-back started (completed springs cannot be cancelled).
|
|
160
|
+
if (generation !== toastGenerationRef.current) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
resumeAutoDismissAfterSwipeRef.current();
|
|
164
|
+
};
|
|
165
|
+
const clearScheduledAutoDismissFromSwipe = () => {
|
|
166
|
+
clearScheduledAutoDismissRef.current();
|
|
73
167
|
};
|
|
168
|
+
const swipeGesture = useMemo(() =>
|
|
169
|
+
// These gesture callbacks need explicit 'worklet' directives because this
|
|
170
|
+
// package ships a pre-built dist compiled by ts-bridge (tsc), which emits the
|
|
171
|
+
// gesture chain as a namespaced call (react_native_gesture_handler_1.Gesture).
|
|
172
|
+
// The consumer's Reanimated/Worklets Babel plugin does run over dist, but its
|
|
173
|
+
// gesture auto-detection doesn't recognize that compiled namespaced form.
|
|
174
|
+
Gesture.Pan()
|
|
175
|
+
.activeOffsetY(TOAST_SWIPE_ACTIVE_OFFSET_Y)
|
|
176
|
+
.failOffsetX([-TOAST_SWIPE_FAIL_OFFSET_X, TOAST_SWIPE_FAIL_OFFSET_X])
|
|
177
|
+
.onStart(() => {
|
|
178
|
+
'worklet';
|
|
179
|
+
// Don't interrupt an in-progress dismiss animation.
|
|
180
|
+
if (isDismissing.value) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
scheduleOnRN(clearScheduledAutoDismissFromSwipe);
|
|
184
|
+
cancelAnimation(translateYProgress);
|
|
185
|
+
gestureStartY.value = translateYProgress.value;
|
|
186
|
+
})
|
|
187
|
+
.onUpdate((event) => {
|
|
188
|
+
'worklet';
|
|
189
|
+
if (isDismissing.value) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const nextTranslateY = gestureStartY.value + event.translationY;
|
|
193
|
+
// Toast sits at the top; only allow dragging upward (more negative).
|
|
194
|
+
translateYProgress.value = Math.min(nextTranslateY, visibleTranslateY.value);
|
|
195
|
+
})
|
|
196
|
+
.onEnd((event) => {
|
|
197
|
+
'worklet';
|
|
198
|
+
if (isDismissing.value) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const { translationY, velocityY } = event;
|
|
202
|
+
const dismissDistance = Math.max(toastHeight.value * TOAST_DISMISS_DISTANCE_THRESHOLD, 24);
|
|
203
|
+
const hasReachedDismissOffset = translationY <= -dismissDistance;
|
|
204
|
+
const hasReachedSwipeThreshold = Math.abs(velocityY) > TOAST_DISMISS_VELOCITY_THRESHOLD;
|
|
205
|
+
const isQuickDismissing = velocityY < 0;
|
|
206
|
+
const shouldDismiss = hasReachedDismissOffset ||
|
|
207
|
+
(hasReachedSwipeThreshold && isQuickDismissing);
|
|
208
|
+
if (shouldDismiss) {
|
|
209
|
+
scheduleOnRN(dismissToastFromSwipe);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const generationAtSpringStart = toastGeneration.value;
|
|
213
|
+
translateYProgress.value = withSpring(visibleTranslateY.value, TOAST_SPRING_CONFIG, (finished) => {
|
|
214
|
+
// A new pan cancels this spring via cancelAnimation; only resume
|
|
215
|
+
// auto-dismiss when the spring-back completed naturally.
|
|
216
|
+
if (finished) {
|
|
217
|
+
scheduleOnRN(resumeAutoDismissFromSwipe, generationAtSpringStart);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}),
|
|
221
|
+
// Shared values and swipe JS wrappers are stable for the component lifetime.
|
|
222
|
+
[]);
|
|
74
223
|
innerRef.current = {
|
|
75
224
|
closeToast,
|
|
76
225
|
showToast,
|
|
@@ -95,30 +244,38 @@ const ToasterComponent = forwardRef(({ twClassName, ...props }, ref) => {
|
|
|
95
244
|
.join(' ');
|
|
96
245
|
const onAnimatedViewLayout = (e) => {
|
|
97
246
|
const { height } = e.nativeEvent.layout;
|
|
98
|
-
const
|
|
99
|
-
const
|
|
247
|
+
const nextHiddenTranslateY = getHiddenTranslateY(height, topOffset);
|
|
248
|
+
const nextVisibleTranslateY = topInset + TOAST_TOP_PADDING;
|
|
249
|
+
hiddenTranslateY.value = nextHiddenTranslateY;
|
|
250
|
+
visibleTranslateY.value = nextVisibleTranslateY;
|
|
100
251
|
toastHeight.value = height;
|
|
101
|
-
|
|
252
|
+
if (animationStartedRef.current) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
animationStartedRef.current = true;
|
|
256
|
+
translateYProgress.value = nextHiddenTranslateY;
|
|
102
257
|
if (toastOptions.hasNoTimeout) {
|
|
103
|
-
translateYProgress.value = withSpring(
|
|
258
|
+
translateYProgress.value = withSpring(nextVisibleTranslateY, TOAST_SPRING_CONFIG);
|
|
104
259
|
}
|
|
105
260
|
else {
|
|
106
|
-
translateYProgress.value = withSpring(
|
|
107
|
-
|
|
108
|
-
scheduleOnRN(
|
|
109
|
-
}
|
|
261
|
+
translateYProgress.value = withSpring(nextVisibleTranslateY, TOAST_SPRING_CONFIG, (finished) => {
|
|
262
|
+
if (finished) {
|
|
263
|
+
scheduleOnRN(beginAutoDismiss);
|
|
264
|
+
}
|
|
110
265
|
});
|
|
111
266
|
}
|
|
112
267
|
};
|
|
113
|
-
return (<
|
|
114
|
-
|
|
268
|
+
return (<GestureDetector gesture={swipeGesture}>
|
|
269
|
+
<Animated.View onLayout={onAnimatedViewLayout} style={baseStyle} {...props}>
|
|
270
|
+
{actionButtonLabel && actionButtonOnPress ? (<Toast {...toastProps} actionButtonLabel={actionButtonLabel} actionButtonOnPress={actionButtonOnPress} onClose={() => {
|
|
115
271
|
closeToast();
|
|
116
272
|
toastOnClose?.();
|
|
117
273
|
}} twClassName={toastTwClassNames}/>) : (<Toast {...restToastProps} onClose={() => {
|
|
118
274
|
closeToast();
|
|
119
275
|
toastOnClose?.();
|
|
120
276
|
}} twClassName={toastTwClassNames}/>)}
|
|
121
|
-
|
|
277
|
+
</Animated.View>
|
|
278
|
+
</GestureDetector>);
|
|
122
279
|
});
|
|
123
280
|
ToasterComponent.displayName = 'Toaster';
|
|
124
281
|
export const Toaster = ToasterComponent;
|