UNPKG

sonner-native

Version:

An opinionated toast component for React Native. A port of @emilkowalski's sonner.

244 lines (242 loc) 9.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getToastContext = exports.ToasterUI = exports.Toaster = void 0; var _react = _interopRequireWildcard(require("react")); var React = _react; var _reactNative = require("react-native"); var _reactNativeScreens = require("react-native-screens"); var _constants = require("./constants.js"); var _context = require("./context.js"); var _positioner = require("./positioner.js"); var _toast = require("./toast.js"); var _toastComparator = require("./toast-comparator.js"); var _animations = require("./animations.js"); 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; } let addToastHandler; let dismissToastHandler; let wiggleHandler; const Toaster = ({ ToasterOverlayWrapper, ...toasterProps }) => { const toastsCounter = React.useRef(1); const toastRefs = React.useRef({}); const [toasts, setToasts] = React.useState([]); const [toastsVisible, setToastsVisible] = React.useState(false); React.useLayoutEffect(() => { if (toasts.length > 0) { setToastsVisible(true); return; } // let the animation finish const timeout = setTimeout(() => { setToastsVisible(false); }, _animations.ANIMATION_DURATION); return () => clearTimeout(timeout); }, [toasts.length]); const props = React.useMemo(() => { return { ...toasterProps, toasts, setToasts, toastsCounter, toastRefs }; }, [toasterProps, toasts]); if (!toastsVisible) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ToasterUI, { ...props }); } if (ToasterOverlayWrapper) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ToasterOverlayWrapper, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ToasterUI, { ...props }) }); } if (_reactNative.Platform.OS === 'ios') { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeScreens.FullWindowOverlay, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ToasterUI, { ...props }) }); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(ToasterUI, { ...props }); }; exports.Toaster = Toaster; const ToasterUI = ({ duration = _constants.toastDefaultValues.duration, position = _constants.toastDefaultValues.position, offset = _constants.toastDefaultValues.offset, visibleToasts = _constants.toastDefaultValues.visibleToasts, swipeToDismissDirection = _constants.toastDefaultValues.swipeToDismissDirection, closeButton, invert, toastOptions = {}, icons, pauseWhenPageIsHidden, gap, theme, autoWiggleOnUpdate, richColors, toasts, setToasts, toastsCounter, toastRefs, ToastWrapper, ...props }) => { addToastHandler = React.useCallback(options => { const id = typeof options?.id === 'number' || options.id && options.id?.length > 0 ? options.id : toastsCounter.current++; setToasts(currentToasts => { const newToast = { ...options, id: options?.id ?? id, variant: options.variant ?? _constants.toastDefaultValues.variant }; const existingToast = currentToasts.find(currentToast => currentToast.id === newToast.id); const shouldUpdate = existingToast && options?.id; if (shouldUpdate) { const shouldWiggle = autoWiggleOnUpdate === 'always' || autoWiggleOnUpdate === 'toast-change' && !(0, _toastComparator.areToastsEqual)(newToast, existingToast); if (shouldWiggle && options.id) { wiggleHandler(options.id); } return currentToasts.map(currentToast => { if (currentToast.id === options.id) { return { ...currentToast, ...newToast, duration: options.duration ?? duration, id: options.id }; } return currentToast; }); } else { const newToasts = [...currentToasts, newToast]; if (!(newToast.id in toastRefs.current)) { toastRefs.current[newToast.id] = /*#__PURE__*/React.createRef(); } if (newToasts.length > visibleToasts) { newToasts.shift(); } return newToasts; } }); return id; }, [toastsCounter, toastRefs, visibleToasts, duration, autoWiggleOnUpdate, setToasts]); const dismissToast = React.useCallback((id, origin) => { if (!id) { toasts.forEach(currentToast => { if (origin === 'onDismiss') { currentToast.onDismiss?.(currentToast.id); } else { currentToast.onAutoClose?.(currentToast.id); } }); setToasts([]); toastsCounter.current = 1; return; } setToasts(currentToasts => currentToasts.filter(currentToast => currentToast.id !== id)); const toastForCallback = toasts.find(currentToast => currentToast.id === id); if (origin === 'onDismiss') { toastForCallback?.onDismiss?.(id); } else { toastForCallback?.onAutoClose?.(id); } return id; }, [setToasts, toasts, toastsCounter]); dismissToastHandler = React.useCallback(id => { return dismissToast(id); }, [dismissToast]); wiggleHandler = React.useCallback(id => { const toastRef = toastRefs.current[id]; if (toastRef && toastRef.current) { toastRef.current.wiggle(); } }, [toastRefs]); const { unstyled } = toastOptions; const value = React.useMemo(() => ({ duration: duration ?? _constants.toastDefaultValues.duration, position: position ?? _constants.toastDefaultValues.position, offset: offset ?? _constants.toastDefaultValues.offset, swipeToDismissDirection: swipeToDismissDirection ?? _constants.toastDefaultValues.swipeToDismissDirection, closeButton: closeButton ?? _constants.toastDefaultValues.closeButton, unstyled: unstyled ?? _constants.toastDefaultValues.unstyled, addToast: addToastHandler, invert: invert ?? _constants.toastDefaultValues.invert, icons: icons ?? {}, pauseWhenPageIsHidden: pauseWhenPageIsHidden ?? _constants.toastDefaultValues.pauseWhenPageIsHidden, gap: gap ?? _constants.toastDefaultValues.gap, theme: theme ?? _constants.toastDefaultValues.theme, toastOptions, autoWiggleOnUpdate: autoWiggleOnUpdate ?? _constants.toastDefaultValues.autoWiggleOnUpdate, richColors: richColors ?? _constants.toastDefaultValues.richColors }), [duration, position, offset, swipeToDismissDirection, closeButton, unstyled, invert, icons, pauseWhenPageIsHidden, gap, theme, toastOptions, autoWiggleOnUpdate, richColors]); const orderToastsFromPosition = React.useCallback(currentToasts => { return position === 'bottom-center' ? currentToasts : currentToasts.slice().reverse(); }, [position]); const onDismiss = React.useCallback(id => { dismissToast(id, 'onDismiss'); }, [dismissToast]); const onAutoClose = React.useCallback(id => { dismissToast(id, 'onAutoClose'); }, [dismissToast]); const allPositions = React.useMemo(() => { return ['top-center', 'bottom-center', 'center']; }, []); const possiblePositions = React.useMemo(() => { return allPositions.filter(possiblePossition => { return toasts.find(positionedToast => positionedToast.position === possiblePossition) || value.position === possiblePossition; }); }, [allPositions, toasts, value.position]); const orderedToasts = React.useMemo(() => { return orderToastsFromPosition(toasts); }, [toasts, orderToastsFromPosition]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_context.ToastContext.Provider, { value: value, children: possiblePositions.map((currentPosition, positionIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_positioner.Positioner, { position: currentPosition, children: orderedToasts.filter(possibleToast => !possibleToast.position && positionIndex === 0 || possibleToast.position === currentPosition).map(toastToRender => { const ToastToRender = /*#__PURE__*/(0, _react.createElement)(_toast.Toast, { ...toastToRender, onDismiss: onDismiss, onAutoClose: onAutoClose, ref: toastRefs.current[toastToRender.id], key: toastToRender.id, ...props }); if (ToastWrapper) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ToastWrapper, { toastId: toastToRender.id, children: ToastToRender }, toastToRender.id); } return ToastToRender; }) }, currentPosition)) }); }; exports.ToasterUI = ToasterUI; const getToastContext = () => { if (!addToastHandler || !dismissToastHandler || !wiggleHandler) { throw new Error('ToastContext is not initialized'); } return { addToast: addToastHandler, dismissToast: dismissToastHandler, wiggleToast: wiggleHandler }; }; exports.getToastContext = getToastContext; //# sourceMappingURL=toaster.js.map