Amba-Agent-App/components/ui/toastProvider.tsx
2026-01-16 00:22:35 +03:00

107 lines
2.5 KiB
TypeScript

import React, { createContext, useContext, useState, useRef } from "react";
import { Animated, Pressable, Text, View, StyleSheet } from "react-native";
import { Portal } from "@gorhom/portal";
const ToastContext = createContext(null);
export const useToast = () => useContext(ToastContext);
export const ToastProvider = ({ children }) => {
const [toast, setToast] = useState(null);
const opacity = useRef(new Animated.Value(0)).current;
const translateY = useRef(new Animated.Value(20)).current;
const show = (options) => {
setToast(options);
Animated.parallel([
Animated.timing(opacity, {
toValue: 1,
duration: 200,
useNativeDriver: true,
}),
Animated.timing(translateY, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}),
]).start();
setTimeout(() => hide(), options.duration || 3000);
};
const hide = () => {
Animated.parallel([
Animated.timing(opacity, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}),
Animated.timing(translateY, {
toValue: 20,
duration: 200,
useNativeDriver: true,
}),
]).start(() => setToast(null));
};
return (
<ToastContext.Provider value={{ show }}>
{children}
<Portal>
{toast && (
<Animated.View
style={[
styles.toastContainer,
{
opacity,
transform: [{ translateY }],
borderLeftColor:
toast.variant === "destructive" ? "#ef4444" : "#4ade80",
},
]}
>
<Pressable onPress={hide} style={styles.toast}>
<Text style={styles.title}>{toast.title}</Text>
{toast.description && (
<Text style={styles.description}>{toast.description}</Text>
)}
</Pressable>
</Animated.View>
)}
</Portal>
</ToastContext.Provider>
);
};
const styles = StyleSheet.create({
toastContainer: {
position: "absolute",
top: 50,
left: 20,
right: 20,
zIndex: 9999,
elevation: 9999,
shadowOpacity: 0.2,
shadowRadius: 8,
shadowOffset: { width: 0, height: 4 },
},
toast: {
backgroundColor: "rgba(30, 30, 30, 0.95)",
borderRadius: 14,
padding: 14,
borderLeftWidth: 4,
},
title: {
color: "white",
fontSize: 16,
fontWeight: "600",
},
description: {
color: "#d4d4d4",
fontSize: 14,
marginTop: 2,
},
});