UNPKG

@backpackapp-io/react-native-toast

Version:

A toasting library for React Native. Built in features such as swipe to dismiss, multiple toasts, & no context power this library.

239 lines (237 loc) 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Toast = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _reactNativeSafeAreaContext = require("react-native-safe-area-context"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _types = require("../core/types"); var _utils = require("../utils"); var _headless = require("../headless"); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const AnimatedPressable = _reactNativeReanimated.default.createAnimatedComponent(_reactNative.Pressable); const DEFAULT_TOAST_HEIGHT = 50; const MAX_WIDTH = 360; const Toast = ({ toast, updateHeight, offset, startPause, endPause, overrideDarkMode, onToastHide, onToastPress, onToastShow, extraInsets, defaultStyle, keyboardVisible, keyboardHeight }) => { const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)(); const { width, height } = (0, _reactNative.useWindowDimensions)(); const isSystemDarkMode = (0, _reactNative.useColorScheme)() === 'dark'; const [toastHeight, setToastHeight] = (0, _react.useState)(toast?.height ? toast.height : DEFAULT_TOAST_HEIGHT); const maxWidth = toast?.maxWidth ? toast.maxWidth : MAX_WIDTH; const [toastWidth, setToastWidth] = (0, _react.useState)(toast?.width ? toast.width : width - 32 > maxWidth ? maxWidth : width - 32); const isDarkMode = overrideDarkMode !== undefined ? overrideDarkMode : isSystemDarkMode; const getStartingPosition = (0, _react.useMemo)(() => { let leftPosition = (width - toastWidth) / 2; // Default to center if (toast.position === _types.ToastPosition.TOP_LEFT || toast.position === _types.ToastPosition.BOTTOM_LEFT) { leftPosition = insets.left + 16 + (extraInsets?.left ?? 0); } if (toast.position === _types.ToastPosition.TOP_RIGHT || toast.position === _types.ToastPosition.BOTTOM_RIGHT) { leftPosition = width - toastWidth - insets.right - 16 - (extraInsets?.right ?? 0); } let startY = 0; if (toast.position === _types.ToastPosition.TOP || toast.position === _types.ToastPosition.TOP_LEFT || toast.position === _types.ToastPosition.TOP_RIGHT) { startY = -(toast.height || DEFAULT_TOAST_HEIGHT) - insets.top - 50; } else { startY = height - insets.bottom - _reactNative.Platform.select({ ios: 16, default: 32 }); } return { startY, leftPosition }; }, [height, width, toastWidth, toast.position, toast.height, insets, extraInsets]); const { startY, leftPosition } = getStartingPosition; const opacity = (0, _reactNativeReanimated.useSharedValue)(0); const position = (0, _reactNativeReanimated.useSharedValue)(startY); const offsetY = (0, _reactNativeReanimated.useSharedValue)(startY); const onPress = (0, _react.useCallback)(() => { if (toast.onPress) { toast.onPress(toast); } if (onToastPress) { onToastPress(toast); } }, [toast, onToastPress]); const dismiss = (0, _react.useCallback)((id, reason) => { _headless.toast.dismiss(id, reason); }, []); const getSwipeDirection = (0, _react.useCallback)(() => { if (toast.position === _types.ToastPosition.TOP || toast.position === _types.ToastPosition.TOP_LEFT || toast.position === _types.ToastPosition.TOP_RIGHT) { return _reactNativeGestureHandler.Directions.UP; } else { return _reactNativeGestureHandler.Directions.DOWN; } }, [toast.position]); const setPosition = (0, _react.useCallback)(() => { let timingConfig = { duration: 300 }; let springConfig = { stiffness: 80 }; if (toast.animationConfig) { const { duration = 300, easing = _reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.quad), reduceMotion = _reactNativeReanimated.ReduceMotion.System, ...spring } = toast.animationConfig; timingConfig = { duration, easing, reduceMotion }; springConfig = spring; } const useSpringAnimation = toast.animationType === 'spring'; const animation = useSpringAnimation ? _reactNativeReanimated.withSpring : _reactNativeReanimated.withTiming; if (toast.position === _types.ToastPosition.TOP || toast.position === _types.ToastPosition.TOP_LEFT || toast.position === _types.ToastPosition.TOP_RIGHT) { offsetY.value = animation(toast.visible ? offset : startY, useSpringAnimation ? springConfig : timingConfig); position.value = animation(toast.visible ? offset : startY, useSpringAnimation ? springConfig : timingConfig); } else { let kbHeight = keyboardVisible ? keyboardHeight : 0; const val = toast.visible ? startY - toastHeight - offset - kbHeight - insets.bottom - (extraInsets?.bottom ?? 0) - _reactNative.Platform.select({ ios: 32, default: 24 }) : startY; offsetY.value = animation(val, useSpringAnimation ? springConfig : timingConfig); position.value = animation(val, useSpringAnimation ? springConfig : timingConfig); } }, [offset, toast.visible, keyboardVisible, keyboardHeight, toastHeight, insets.bottom, position, startY, toast.position, offsetY, extraInsets, toast.animationConfig, toast.animationType]); const composedGesture = (0, _react.useMemo)(() => { const panGesture = _reactNativeGestureHandler.Gesture.Pan().onUpdate(e => { offsetY.value = e.translationY / 4 + position.value; }).onEnd(() => { (0, _reactNativeReanimated.runOnJS)(setPosition)(); }); const flingGesture = _reactNativeGestureHandler.Gesture.Fling().direction(getSwipeDirection()).onEnd(() => { offsetY.value = (0, _reactNativeReanimated.withTiming)(startY, { duration: toast?.animationConfig?.flingPositionReturnDuration ?? 40 }); (0, _reactNativeReanimated.runOnJS)(dismiss)(toast.id, _types.DismissReason.SWIPE); }); return toast.isSwipeable ? _reactNativeGestureHandler.Gesture.Simultaneous(flingGesture, panGesture) : panGesture; }, [offsetY, startY, position, setPosition, toast.id, dismiss, toast.isSwipeable, toast.animationConfig, getSwipeDirection]); (0, _utils.useVisibilityChange)(() => { if (toast.onShow) { toast.onShow(toast); } onToastShow?.(toast); }, reason => { if (toast.onHide) { toast.onHide(toast, reason || _types.DismissReason.PROGRAMMATIC); } onToastHide?.(toast, reason || _types.DismissReason.PROGRAMMATIC); }, toast.visible, toast.dismissReason); (0, _react.useEffect)(() => { setToastHeight(toast?.height ? toast.height : DEFAULT_TOAST_HEIGHT); }, [toast.height]); (0, _react.useEffect)(() => { setToastWidth(toast?.width ? toast.width : width - 32 > maxWidth ? maxWidth : width - 32); }, [toast.width, maxWidth, width]); (0, _react.useEffect)(() => { opacity.value = (0, _reactNativeReanimated.withTiming)(toast.visible ? 1 : 0, { duration: toast?.animationConfig?.duration ?? 300 }); }, [toast.visible, opacity, toast.animationConfig]); (0, _react.useEffect)(() => { setPosition(); }, [offset, toast.visible, keyboardVisible, keyboardHeight, toastHeight, setPosition]); const style = (0, _reactNativeReanimated.useAnimatedStyle)(() => { //Control opacity and translation of toast return { opacity: opacity.value, transform: [{ translateY: offsetY.value }] }; }); const resolvedValue = (0, _types.resolveValue)(toast.message, toast); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, { gesture: composedGesture, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(AnimatedPressable, { testID: "toast-pressable", onPressIn: startPause, onPressOut: () => { endPause(); }, onPress: onPress, style: [{ backgroundColor: !toast.customToast ? isDarkMode ? _utils.colors.backgroundDark : _utils.colors.backgroundLight : undefined, borderRadius: 8, position: 'absolute', left: leftPosition, zIndex: toast.visible ? 9999 : undefined, alignItems: 'center', justifyContent: 'center' }, style, !toast.disableShadow && (0, _utils.ConstructShadow)('#181821', 0.15, false), defaultStyle?.pressable, toast.styles?.pressable], children: toast.customToast ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { testID: "toast-view", onLayout: event => updateHeight(toast.id, event.nativeEvent.layout.height), children: toast.customToast({ ...toast, height: toastHeight, width: toastWidth }) }, toast.id) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { testID: "toast-view", onLayout: event => updateHeight(toast.id, event.nativeEvent.layout.height), style: [{ minHeight: toastHeight, width: toastWidth, flexDirection: 'row', alignItems: 'center', paddingVertical: 12, paddingHorizontal: 16 }, defaultStyle?.view, toast.styles?.view], children: [(toast.type === 'error' || toast.type === 'success') && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [{ backgroundColor: toast.type === 'error' ? _utils.colors.error : toast.type === 'success' ? _utils.colors.success : isDarkMode ? _utils.colors.backgroundDark : _utils.colors.backgroundLight, width: 3, height: '100%', borderRadius: 12, marginRight: 12 }, defaultStyle?.indicator, toast?.styles?.indicator] }), typeof toast.icon === 'string' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { children: toast.icon }) : toast.icon, typeof resolvedValue === 'string' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [{ color: isDarkMode ? _utils.colors.textLight : _utils.colors.textDark, padding: 4, flex: 1 }, defaultStyle?.text, toast?.styles?.text], children: resolvedValue }) : resolvedValue] }, toast.id) }) }, toast.id); }; exports.Toast = Toast; //# sourceMappingURL=Toast.js.map