From 527331143c2f5b6f8a84d7684244c6f8ddf9fe5a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 13 Aug 2025 11:36:05 -0500 Subject: [PATCH] Native --- src/components/Toast/index.tsx | 117 ++++++++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 15 deletions(-) diff --git a/src/components/Toast/index.tsx b/src/components/Toast/index.tsx index c13feeb72d..a479bb7e74 100644 --- a/src/components/Toast/index.tsx +++ b/src/components/Toast/index.tsx @@ -18,6 +18,7 @@ import Animated, { } from 'react-native-reanimated' import RootSiblings from 'react-native-root-siblings' import {useSafeAreaInsets} from 'react-native-safe-area-context' +import {Motion} from '@legendapp/motion' import {nanoid} from 'nanoid/non-secure' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' @@ -36,6 +37,8 @@ export {useToast} from '#/components/Toast/Context' export {Outlet} from '#/components/Toast/Portal' const TOAST_ANIMATION_DURATION = 300 +const ANIMATION_DURATION = 300 +const TOAST_GAP = 8 // Gap between toasts export function ToastProvider({ children, @@ -48,24 +51,54 @@ export function ToastProvider({ const [toasts, setToasts] = useState< { id: string - toast: ToastProps - timeout: NodeJS.Timeout + props: ToastProps + dimensions: { + width: number | undefined + height: number | undefined + } + setDimensions: (width: number, height: number) => void + exiting: boolean + timers: NodeJS.Timeout[] }[] >([]) const show = useCallback(props => { - AccessibilityInfo.announceForAccessibility(props.a11yLabel) - setToasts(prevToasts => { const id = nanoid() + const duration = props.duration || DEFAULT_TOAST_DURATION return [ ...prevToasts, { id, - toast: props, - timeout: setTimeout(() => { - setToasts(currentToasts => currentToasts.filter(t => t.id !== id)) - }, props.duration || DEFAULT_TOAST_DURATION), + props, + dimensions: {width: undefined, height: undefined}, + exiting: false, + setDimensions: (width: number, height: number) => { + setToasts(currentToasts => + currentToasts.map(t => { + if (t.id === id) { + t.dimensions.width = width + t.dimensions.height = height + } + return t + }), + ) + }, + timers: [ + setTimeout(() => { + setToasts(currentToasts => + currentToasts.map(t => { + if (t.id === id) { + t.exiting = true + } + return t + }), + ) + }, duration), + setTimeout(() => { + setToasts(currentToasts => currentToasts.filter(t => t.id !== id)) + }, duration + ANIMATION_DURATION), + ], }, ] }) @@ -74,8 +107,8 @@ export function ToastProvider({ useEffect(() => { return () => { setToasts(toasts => { - toasts.map(({timeout}) => { - clearTimeout(timeout) + toasts.map(({timers}) => { + timers.map(clearTimeout) }) return toasts }) @@ -99,17 +132,71 @@ export function ToastProvider({ - {toasts.map(({id, toast}) => ( - - ))} + {toasts.map(toast => { + const isReady = !!toast.dimensions.width + const toastComponent = ( + + ) + + if (!isReady) { + return ( + + { + if (toast.dimensions.width) return + toast.setDimensions( + e.nativeEvent.layout.width, + e.nativeEvent.layout.height, + ) + }}> + {toastComponent} + + + ) + } + + return ( + + + + + + ) + })} ) : null}