cdslibrary 1.2.100 → 1.2.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,7 +10,7 @@ import Animated, {
|
|
|
10
10
|
import { useTheme } from "../context/CDSThemeContext";
|
|
11
11
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
|
12
12
|
|
|
13
|
-
export const CDSAccordion = ({ title, description, children, defaultExpanded = false }) => {
|
|
13
|
+
export const CDSAccordion = ({ title, description, children, defaultExpanded = false, onToggle }) => {
|
|
14
14
|
const { theme } = useTheme();
|
|
15
15
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
16
16
|
const [contentHeight, setContentHeight] = useState(0); // Altura real medida
|
|
@@ -21,6 +21,10 @@ export const CDSAccordion = ({ title, description, children, defaultExpanded = f
|
|
|
21
21
|
const newValue = !expanded;
|
|
22
22
|
setExpanded(newValue);
|
|
23
23
|
|
|
24
|
+
if (onToggle) {
|
|
25
|
+
onToggle(newValue);
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
animation.value = withTiming(newValue ? 1 : 0, {
|
|
25
29
|
duration: 250,
|
|
26
30
|
easing: Easing.bezier(0.4, 0, 0.2, 1)
|
|
@@ -88,7 +92,7 @@ export const CDSAccordion = ({ title, description, children, defaultExpanded = f
|
|
|
88
92
|
{/* CONTENEDOR DE MEDICIÓN: Es invisible y absoluto, solo sirve para saber cuánto mide el children */}
|
|
89
93
|
<View
|
|
90
94
|
onLayout={onLayout}
|
|
91
|
-
style={[styles.measureContainer, {pointerEvents: 'none'}]}
|
|
95
|
+
style={[styles.measureContainer, { pointerEvents: 'none' }]}
|
|
92
96
|
>
|
|
93
97
|
<View style={{ paddingVertical: theme.space.md, gap: theme.space.md }}>
|
|
94
98
|
{description && (
|
|
@@ -136,7 +140,7 @@ const styles = StyleSheet.create({
|
|
|
136
140
|
position: 'absolute',
|
|
137
141
|
left: 16,
|
|
138
142
|
right: 16,
|
|
139
|
-
opacity: 0,
|
|
143
|
+
opacity: 0,
|
|
140
144
|
},
|
|
141
145
|
paddingWrapper: {
|
|
142
146
|
paddingBottom: 16,
|
|
@@ -4,7 +4,7 @@ import { MaterialIcons } from "@expo/vector-icons";
|
|
|
4
4
|
import { useTheme } from "../context/CDSThemeContext";
|
|
5
5
|
import { CDSTooltip } from "./CDSTooltip"; // Asegúrate de importar tu Tooltip
|
|
6
6
|
|
|
7
|
-
export const CDSImageButton = ({ object, isActive, onPress, hasHelper, helperMessage, arrowAlignment, isGrid }) => {
|
|
7
|
+
export const CDSImageButton = ({ object, isActive, onPress, hasHelper, onPressHelper, helperMessage, arrowAlignment, isGrid }) => {
|
|
8
8
|
const { theme } = useTheme();
|
|
9
9
|
|
|
10
10
|
// Estados para controlar el Tooltip interno
|
|
@@ -12,7 +12,9 @@ export const CDSImageButton = ({ object, isActive, onPress, hasHelper, helperMes
|
|
|
12
12
|
const [tooltipPos, setTooltipPos] = useState({ x: 0, y: 0 });
|
|
13
13
|
|
|
14
14
|
const handleHelperPress = (event) => {
|
|
15
|
-
|
|
15
|
+
if (onPressHelper) {
|
|
16
|
+
onPressHelper(object);
|
|
17
|
+
}
|
|
16
18
|
if (event.target && event.target.getBoundingClientRect) {
|
|
17
19
|
const rect = event.target.getBoundingClientRect();
|
|
18
20
|
setTooltipPos({
|
|
@@ -42,7 +44,7 @@ export const CDSImageButton = ({ object, isActive, onPress, hasHelper, helperMes
|
|
|
42
44
|
style={[
|
|
43
45
|
styles.mainContainer,
|
|
44
46
|
{
|
|
45
|
-
width: isGrid ? 192 : 'auto'
|
|
47
|
+
width: isGrid ? 192 : 'auto',
|
|
46
48
|
maxWidth: isGrid ? 192 : 160,
|
|
47
49
|
backgroundColor: isActive
|
|
48
50
|
? theme.surface.neutral.primaryVariant
|
|
@@ -3,7 +3,7 @@ import { View, Animated, StyleSheet, ScrollView } from 'react-native';
|
|
|
3
3
|
import { CDSImageButton } from './CDSImageButton';
|
|
4
4
|
import { useTheme } from "../context/CDSThemeContext";
|
|
5
5
|
|
|
6
|
-
export const CDSImageButtonGroup = ({ array, onSelect, isCentered, isGrid }) => {
|
|
6
|
+
export const CDSImageButtonGroup = ({ array, onSelect, isCentered, isGrid, onPressHelper }) => {
|
|
7
7
|
const { theme } = useTheme();
|
|
8
8
|
const isMobile = theme.isMobile
|
|
9
9
|
const [selectedId, setSelectedId] = useState(null);
|
|
@@ -73,6 +73,7 @@ export const CDSImageButtonGroup = ({ array, onSelect, isCentered, isGrid }) =>
|
|
|
73
73
|
onPress={() => handlePress(item.id)}
|
|
74
74
|
hasHelper={!!item.helper}
|
|
75
75
|
helperMessage={item.helper}
|
|
76
|
+
onPressHelper={onPressHelper}
|
|
76
77
|
arrowAlignment={item.arrowAlignment}
|
|
77
78
|
// Opcional: Ajustar ancho en grid
|
|
78
79
|
style={isGrid ? { width: '47%' } : undefined}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
|
-
import { StyleSheet, Text, TouchableOpacity,
|
|
2
|
+
import { StyleSheet, Text, TouchableOpacity, } from "react-native";
|
|
3
3
|
import Animated, {
|
|
4
4
|
useSharedValue,
|
|
5
5
|
useAnimatedStyle,
|
|
6
6
|
withSpring,
|
|
7
7
|
withTiming,
|
|
8
|
-
runOnJS
|
|
8
|
+
runOnJS,
|
|
9
|
+
interpolate
|
|
9
10
|
} from "react-native-reanimated";
|
|
10
11
|
import { GestureDetector, Gesture, } from "react-native-gesture-handler";
|
|
11
12
|
import { useTheme } from "../context/CDSThemeContext";
|
|
@@ -13,61 +14,59 @@ import { useTheme } from "../context/CDSThemeContext";
|
|
|
13
14
|
|
|
14
15
|
export const CDSSnackBar = ({ message, visible, onDismiss, action }) => {
|
|
15
16
|
const { theme } = useTheme();
|
|
16
|
-
const translateY = useSharedValue(
|
|
17
|
+
const translateY = useSharedValue(150); // Empezamos ocultos abajo
|
|
17
18
|
|
|
18
|
-
//
|
|
19
|
+
// 1. UN SOLO useEffect para controlar la entrada y salida
|
|
19
20
|
useEffect(() => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
translateY.value = withTiming(150);
|
|
24
|
-
}
|
|
21
|
+
translateY.value = withTiming(visible ? 0 : 150, {
|
|
22
|
+
duration: 300
|
|
23
|
+
});
|
|
25
24
|
}, [visible]);
|
|
26
25
|
|
|
27
|
-
//
|
|
26
|
+
// 2. Timer de auto-ocultado (solo si es visible)
|
|
28
27
|
useEffect(() => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
if (!visible) return;
|
|
29
|
+
|
|
30
|
+
const timer = setTimeout(() => {
|
|
31
|
+
if (onDismiss) onDismiss();
|
|
32
|
+
}, 4000);
|
|
33
|
+
|
|
35
34
|
return () => clearTimeout(timer);
|
|
36
35
|
}, [visible, onDismiss]);
|
|
37
36
|
|
|
38
|
-
// Configuración del Gesto (Pan Gesture)
|
|
39
37
|
const gesture = Gesture.Pan()
|
|
40
38
|
.onUpdate((event) => {
|
|
41
|
-
|
|
42
|
-
if (event.translationY > 0) {
|
|
43
|
-
translateY.value = event.translationY;
|
|
44
|
-
}
|
|
39
|
+
if (event.translationY > 0) translateY.value = event.translationY;
|
|
45
40
|
})
|
|
46
41
|
.onEnd((event) => {
|
|
47
|
-
// Si se arrastró más de 50px o la velocidad es alta, cerramos
|
|
48
42
|
if (event.translationY > 50 || event.velocityY > 500) {
|
|
49
43
|
translateY.value = withTiming(150, {}, () => {
|
|
50
44
|
if (onDismiss) runOnJS(onDismiss)();
|
|
51
45
|
});
|
|
52
46
|
} else {
|
|
53
|
-
// Si no, regresa a su posición original
|
|
54
47
|
translateY.value = withSpring(0);
|
|
55
48
|
}
|
|
56
49
|
});
|
|
57
50
|
|
|
58
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
});
|
|
51
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
52
|
+
transform: [{ translateY: translateY.value }],
|
|
53
|
+
// OPCIONAL: Añadimos opacidad para que no se vea el "fantasma" si se queda trabado
|
|
54
|
+
opacity: interpolate(translateY.value, [0, 100], [1, 0]),
|
|
55
|
+
}));
|
|
65
56
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
// IMPORTANTE: Eliminamos el "if (!visible) return null" manual para dejar
|
|
58
|
+
// que Reanimated maneje la salida. Si quieres optimizar, usa un estado local:
|
|
59
|
+
const [shouldRender, setShouldRender] = React.useState(visible);
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (visible) setShouldRender(true);
|
|
63
|
+
else {
|
|
64
|
+
const timer = setTimeout(() => setShouldRender(false), 400);
|
|
65
|
+
return () => clearTimeout(timer);
|
|
66
|
+
}
|
|
67
|
+
}, [visible]);
|
|
68
|
+
|
|
69
|
+
if (!shouldRender) return null;
|
|
71
70
|
|
|
72
71
|
return (
|
|
73
72
|
<GestureDetector gesture={gesture}>
|
|
@@ -83,18 +82,12 @@ export const CDSSnackBar = ({ message, visible, onDismiss, action }) => {
|
|
|
83
82
|
}
|
|
84
83
|
]}
|
|
85
84
|
>
|
|
86
|
-
<Text style={[
|
|
87
|
-
theme.typography.regular.sm,
|
|
88
|
-
{ color: theme.text.neutral.contrast, flex: 1 }
|
|
89
|
-
]}>
|
|
85
|
+
<Text style={[theme.typography.regular.sm, { color: theme.text.neutral.contrast, flex: 1 }]}>
|
|
90
86
|
{message}
|
|
91
87
|
</Text>
|
|
92
|
-
|
|
93
88
|
{action && (
|
|
94
89
|
<TouchableOpacity onPress={onDismiss} style={styles.actionButton}>
|
|
95
|
-
<Text style={[theme.typography.label, {
|
|
96
|
-
color: theme.text.neutral.contrast,
|
|
97
|
-
}]}>
|
|
90
|
+
<Text style={[theme.typography.label, { color: theme.text.neutral.contrast }]}>
|
|
98
91
|
{action}
|
|
99
92
|
</Text>
|
|
100
93
|
</TouchableOpacity>
|
|
@@ -113,8 +106,8 @@ const styles = StyleSheet.create({
|
|
|
113
106
|
flexDirection: 'row',
|
|
114
107
|
alignItems: 'center',
|
|
115
108
|
justifyContent: 'space-between',
|
|
116
|
-
bottom: 40,
|
|
117
|
-
zIndex: 9999,
|
|
109
|
+
bottom: 40,
|
|
110
|
+
zIndex: 9999,
|
|
118
111
|
elevation: 10,
|
|
119
112
|
},
|
|
120
113
|
actionButton: {
|