eletrotupi / tcc/ frontend/components/ui/Toast.tsxad95ceb1d7d44db7a364485d77c18e8e3c2a4392
2.2 KB | 93 lines Raw
1
import React, { useEffect, useState } from 'react';
2
import { Animated, StyleSheet } from 'react-native';
3
import { Text } from '@/components/ui/Text';
4
import { useSafeAreaInsets } from 'react-native-safe-area-context';
5

6
export type ToastVariant = 'error' | 'success' | 'warning';
7

8
interface ToastProps {
9
  message: string;
10
  variant: ToastVariant;
11
  visible: boolean;
12
}
13

14
const VARIANT_COLORS: Record<ToastVariant, string> = {
15
  error: '#EF4444',
16
  success: '#22c55e',
17
  warning: '#F97316',
18
};
19

20
export function Toast({ message, variant, visible }: ToastProps) {
21
  const insets = useSafeAreaInsets();
22
  const [translateY] = useState(() => new Animated.Value(-120));
23
  const [opacity] = useState(() => new Animated.Value(0));
24

25
  useEffect(() => {
26
    if (visible) {
27
      Animated.parallel([
28
        Animated.spring(translateY, {
29
          toValue: 0,
30
          useNativeDriver: true,
31
          tension: 80,
32
          friction: 10,
33
        }),
34
        Animated.timing(opacity, {
35
          toValue: 1,
36
          duration: 200,
37
          useNativeDriver: true,
38
        }),
39
      ]).start();
40
    } else {
41
      Animated.parallel([
42
        Animated.timing(translateY, {
43
          toValue: -120,
44
          duration: 250,
45
          useNativeDriver: true,
46
        }),
47
        Animated.timing(opacity, {
48
          toValue: 0,
49
          duration: 200,
50
          useNativeDriver: true,
51
        }),
52
      ]).start();
53
    }
54
  }, [visible, translateY, opacity]);
55

56
  return (
57
    <Animated.View
58
      style={[
59
        styles.container,
60
        { top: insets.top + 12, backgroundColor: VARIANT_COLORS[variant] },
61
        { transform: [{ translateY }], opacity },
62
      ]}
63
      pointerEvents="none"
64
    >
65
      <Text style={styles.message} numberOfLines={3}>
66
        {message}
67
      </Text>
68
    </Animated.View>
69
  );
70
}
71

72
const styles = StyleSheet.create({
73
  container: {
74
    position: 'absolute',
75
    left: 16,
76
    right: 16,
77
    zIndex: 9999,
78
    borderRadius: 10,
79
    paddingHorizontal: 16,
80
    paddingVertical: 12,
81
    shadowColor: '#000',
82
    shadowOffset: { width: 0, height: 4 },
83
    shadowOpacity: 0.15,
84
    shadowRadius: 8,
85
    elevation: 8,
86
  },
87
  message: {
88
    color: '#fff',
89
    fontSize: 14,
90
    fontWeight: '500',
91
    lineHeight: 20,
92
  },
93
});