UNPKG

sonner-native

Version:

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

97 lines (88 loc) 2.84 kB
import { ESTIMATED_TOAST_HEIGHT } from './constants'; import type { ToastPosition, ToastProps } from './types'; export const getOrderedToastIds = ( toasts: ToastProps[], position: ToastPosition, enableStacking: boolean ): Array<string | number> => { if (enableStacking) { // toasts are already in rendering order (reversed by orderToastsFromPosition for top-center) return toasts.map((t) => t.id); } return position === 'top-center' ? toasts.map((t) => t.id).reverse() : toasts.map((t) => t.id); }; export const calculateToastPosition = ({ index, numberOfToasts, enableStacking, position, allToastHeights, gap, orderedToastIds, isExpanded, stackGap, }: { index: number; numberOfToasts: number; enableStacking: boolean; position: ToastPosition; allToastHeights: Record<string | number, number>; gap: number; orderedToastIds: Array<string | number>; isExpanded: boolean; stackGap: number; }): number => { 'worklet'; const effectiveEnableStacking = enableStacking && !isExpanded; // Center anchors at top:50% of the screen (top edge of toast = center line). // Shift by -frontHeight/2 so the front toast is visually centered on the line. const centerShift = position === 'center' ? -( (allToastHeights[orderedToastIds[numberOfToasts - 1]!] || ESTIMATED_TOAST_HEIGHT) / 2 ) : 0; if (effectiveEnableStacking) { const currentId = orderedToastIds[index]; const currentHeight = allToastHeights[currentId!] || ESTIMATED_TOAST_HEIGHT; if (position === 'top-center') { const frontId = orderedToastIds[0]; const frontHeight = allToastHeights[frontId!] || ESTIMATED_TOAST_HEIGHT; return frontHeight + index * stackGap - currentHeight; } // bottom-center and center const frontId = orderedToastIds[numberOfToasts - 1]; const frontHeight = allToastHeights[frontId!] || ESTIMATED_TOAST_HEIGHT; const distFromFront = numberOfToasts - 1 - index; return ( centerShift - (frontHeight + distFromFront * stackGap - currentHeight) ); } const effectiveGap = isExpanded ? stackGap : gap; if (position === 'top-center') { let totalOffset = 0; for (let i = 0; i < index; i++) { const toastId = orderedToastIds[i]; if (!toastId) { continue; } const height = allToastHeights[toastId] || ESTIMATED_TOAST_HEIGHT; totalOffset += height + effectiveGap; } return totalOffset; } // bottom-center and center let totalOffset = 0; for (let i = numberOfToasts - 1; i > index; i--) { const toastId = orderedToastIds[i]; if (!toastId) { continue; } const height = allToastHeights[toastId] || ESTIMATED_TOAST_HEIGHT; totalOffset += height + effectiveGap; } return centerShift - totalOffset; };