cdslibrary 1.2.41 → 1.2.43
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.
- package/components/CDSAccordion.jsx +5 -5
- package/components/CDSInput.jsx +84 -47
- package/components/CDSSnackBar.jsx +79 -45
- package/index.js +4 -3
- package/package.json +2 -2
- package/tokens/CDSsemanticColors.js +2 -0
|
@@ -49,7 +49,7 @@ export const CDSAccordion = ({ title, description, children, defaultExpanded = f
|
|
|
49
49
|
styles.container,
|
|
50
50
|
{
|
|
51
51
|
backgroundColor: theme.surface.neutral.primary,
|
|
52
|
-
borderRadius: theme.radius.
|
|
52
|
+
borderRadius: theme.radius.md,
|
|
53
53
|
borderColor: theme.outline.neutral.primary,
|
|
54
54
|
borderWidth: 1
|
|
55
55
|
}
|
|
@@ -59,11 +59,11 @@ export const CDSAccordion = ({ title, description, children, defaultExpanded = f
|
|
|
59
59
|
style={[
|
|
60
60
|
styles.header,
|
|
61
61
|
{
|
|
62
|
-
borderTopRightRadius: theme.radius.
|
|
63
|
-
borderTopLeftRadius: theme.radius.
|
|
62
|
+
borderTopRightRadius: theme.radius.md,
|
|
63
|
+
borderTopLeftRadius: theme.radius.md,
|
|
64
64
|
// Si no está expandido, redondeamos también abajo
|
|
65
|
-
borderBottomRightRadius: expanded ? 0 : theme.radius.
|
|
66
|
-
borderBottomLeftRadius: expanded ? 0 : theme.radius.
|
|
65
|
+
borderBottomRightRadius: expanded ? 0 : theme.radius.md,
|
|
66
|
+
borderBottomLeftRadius: expanded ? 0 : theme.radius.md,
|
|
67
67
|
},
|
|
68
68
|
expanded && {
|
|
69
69
|
backgroundColor: theme.surface.brand.primary,
|
package/components/CDSInput.jsx
CHANGED
|
@@ -1,29 +1,64 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { View, Text, TextInput, StyleSheet, Platform } from "react-native";
|
|
1
|
+
import React, { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { View, Text, TextInput, StyleSheet, Platform } from "react-native";
|
|
3
|
+
import Animated, {
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
useSharedValue,
|
|
6
|
+
withSequence,
|
|
7
|
+
withTiming,
|
|
8
|
+
interpolateColor
|
|
9
|
+
} from "react-native-reanimated";
|
|
3
10
|
import { useTheme } from "../context/CDSThemeContext";
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeText }) => {
|
|
12
|
+
export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeText, animationTrigger }) => {
|
|
7
13
|
const { theme } = useTheme();
|
|
8
14
|
const [isFocused, setIsFocused] = useState(false);
|
|
15
|
+
|
|
16
|
+
// Valor animado para el "flash" (0 a 1)
|
|
17
|
+
const flashValue = useSharedValue(0);
|
|
18
|
+
// Ref para detectar si el cambio vino del teclado o del código
|
|
19
|
+
const isInternalChange = useRef(false);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!isInternalChange.current) {
|
|
23
|
+
flashValue.value = withSequence(
|
|
24
|
+
withTiming(1, { duration: 200 }),
|
|
25
|
+
withTiming(0, { duration: 600 })
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
isInternalChange.current = false;
|
|
29
|
+
}, [value, animationTrigger]);
|
|
9
30
|
|
|
10
31
|
const handleTextChange = (inputText) => {
|
|
32
|
+
isInternalChange.current = true; // Marcamos que el cambio es del usuario
|
|
33
|
+
|
|
11
34
|
if (keyboard === "numeric" || keyboard === "decimal-pad") {
|
|
12
|
-
let cleaned = inputText.replace(',', '.');
|
|
13
|
-
cleaned = cleaned.replace(/[^0-9.]/g, "");
|
|
14
|
-
|
|
35
|
+
let cleaned = inputText.replace(',', '.').replace(/[^0-9.]/g, "");
|
|
15
36
|
const parts = cleaned.split('.');
|
|
16
|
-
if (parts.length > 2)
|
|
17
|
-
cleaned = parts[0] + '.' + parts.slice(1).join('');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Enviamos el valor limpio al padre (index.js)
|
|
37
|
+
if (parts.length > 2) cleaned = parts[0] + '.' + parts.slice(1).join('');
|
|
21
38
|
onChangeText && onChangeText(cleaned);
|
|
22
39
|
} else {
|
|
23
40
|
onChangeText && onChangeText(inputText);
|
|
24
41
|
}
|
|
25
42
|
};
|
|
26
43
|
|
|
44
|
+
// Estilo animado para el borde y el fondo
|
|
45
|
+
const animatedBoxStyle = useAnimatedStyle(() => {
|
|
46
|
+
const borderColor = interpolateColor(
|
|
47
|
+
flashValue.value,
|
|
48
|
+
[0, 1],
|
|
49
|
+
[
|
|
50
|
+
isFocused ? theme.outline.neutral.focus : value ? theme.outline.neutral.tertiaryVariant : theme.outline.neutral.primary,
|
|
51
|
+
theme.outline.neutral.focus// Color del "brillo" (usamos el color de focus)
|
|
52
|
+
]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
borderColor: borderColor,
|
|
57
|
+
transform: [{ scale: 1 + flashValue.value * 0.02 }], // Pequeño pulso
|
|
58
|
+
borderWidth: 1 + flashValue.value * 1,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
|
|
27
62
|
return (
|
|
28
63
|
<View style={[styles.container, { gap: theme.space.sm }]}>
|
|
29
64
|
{label && (
|
|
@@ -32,49 +67,51 @@ export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeTe
|
|
|
32
67
|
</Text>
|
|
33
68
|
)}
|
|
34
69
|
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
theme.typography.inputText.value,
|
|
40
|
-
{
|
|
70
|
+
<Animated.View style={[
|
|
71
|
+
styles.wrapper,
|
|
72
|
+
animatedBoxStyle,
|
|
73
|
+
{
|
|
41
74
|
backgroundColor: type === 'readOnly' ? theme.surface.action.disabled : theme.surface.neutral.primary,
|
|
42
|
-
borderColor: isFocused
|
|
43
|
-
? theme.outline.neutral.focus
|
|
44
|
-
: value ? theme.outline.neutral.tertiaryVariant // Cambiado 'text' por 'value'
|
|
45
|
-
: theme.outline.neutral.primary,
|
|
46
75
|
borderRadius: theme.radius.sm,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
}
|
|
77
|
+
]}>
|
|
78
|
+
<TextInput
|
|
79
|
+
pointerEvents={type === 'readOnly' ? 'none' : 'auto'}
|
|
80
|
+
style={[
|
|
81
|
+
styles.textBox,
|
|
82
|
+
theme.typography.inputText.value,
|
|
83
|
+
{
|
|
84
|
+
paddingHorizontal: theme.space.sm,
|
|
85
|
+
color: theme.text.neutral.primary,
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
outlineStyle: 'none',
|
|
88
|
+
},
|
|
89
|
+
]}
|
|
90
|
+
placeholder={placeholder}
|
|
91
|
+
placeholderTextColor={theme.text.neutral.placeholder}
|
|
92
|
+
keyboardType={keyboard === "numeric" ? (Platform.OS === 'ios' ? 'decimal-pad' : 'numeric') : keyboard}
|
|
93
|
+
onChangeText={handleTextChange}
|
|
94
|
+
value={value}
|
|
95
|
+
editable={type !== 'readOnly'}
|
|
96
|
+
secureTextEntry={type === "password"}
|
|
97
|
+
onFocus={() => setIsFocused(true)}
|
|
98
|
+
onBlur={() => setIsFocused(false)}
|
|
99
|
+
underlineColorAndroid="transparent"
|
|
100
|
+
/>
|
|
101
|
+
</Animated.View>
|
|
63
102
|
</View>
|
|
64
103
|
);
|
|
65
104
|
};
|
|
66
105
|
|
|
67
106
|
const styles = StyleSheet.create({
|
|
68
107
|
container: { width: "100%" },
|
|
69
|
-
|
|
70
|
-
borderWidth: 1,
|
|
108
|
+
wrapper: {
|
|
71
109
|
height: 48,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
110
|
+
borderWidth: 1,
|
|
111
|
+
justifyContent: 'center',
|
|
112
|
+
},
|
|
113
|
+
textBox: {
|
|
114
|
+
flex: 1,
|
|
115
|
+
height: '100%',
|
|
79
116
|
},
|
|
80
117
|
});
|
|
@@ -1,60 +1,99 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
|
-
import { StyleSheet, Text, TouchableOpacity } from "react-native";
|
|
3
|
-
import Animated, {
|
|
2
|
+
import { StyleSheet, Text, TouchableOpacity, Dimensions } from "react-native";
|
|
3
|
+
import Animated, {
|
|
4
|
+
useSharedValue,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
withSpring,
|
|
7
|
+
withTiming,
|
|
8
|
+
runOnJS
|
|
9
|
+
} from "react-native-reanimated";
|
|
10
|
+
import { GestureDetector, Gesture, } from "react-native-gesture-handler";
|
|
4
11
|
import { useTheme } from "../context/CDSThemeContext";
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
const { height: SCREEN_HEIGHT } = Dimensions.get("window");
|
|
14
|
+
|
|
15
|
+
export const CDSSnackBar = ({ message, visible, onDismiss, action }) => {
|
|
7
16
|
const { theme } = useTheme();
|
|
17
|
+
const translateY = useSharedValue(100); // Empezamos fuera de pantalla
|
|
18
|
+
|
|
19
|
+
// Sincronizar visibilidad con animación
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (visible) {
|
|
22
|
+
translateY.value = withSpring(0, { damping: 15 });
|
|
23
|
+
} else {
|
|
24
|
+
translateY.value = withTiming(150);
|
|
25
|
+
}
|
|
26
|
+
}, [visible]);
|
|
8
27
|
|
|
28
|
+
// Lógica de auto-ocultado
|
|
9
29
|
useEffect(() => {
|
|
10
30
|
let timer;
|
|
11
31
|
if (visible) {
|
|
12
|
-
// Configuramos el temporizador a 5000ms (5 segundos)
|
|
13
32
|
timer = setTimeout(() => {
|
|
14
33
|
if (onDismiss) onDismiss();
|
|
15
|
-
},
|
|
34
|
+
}, 4000);
|
|
16
35
|
}
|
|
17
|
-
|
|
18
|
-
// Limpieza: si el componente se desmonta o el usuario lo cierra antes,
|
|
19
|
-
// cancelamos el timer para evitar fugas de memoria.
|
|
20
36
|
return () => clearTimeout(timer);
|
|
21
37
|
}, [visible, onDismiss]);
|
|
22
38
|
|
|
23
|
-
//
|
|
24
|
-
|
|
39
|
+
// Configuración del Gesto (Pan Gesture)
|
|
40
|
+
const gesture = Gesture.Pan()
|
|
41
|
+
.onUpdate((event) => {
|
|
42
|
+
// Solo permitimos arrastrar hacia abajo (valores positivos de Y)
|
|
43
|
+
if (event.translationY > 0) {
|
|
44
|
+
translateY.value = event.translationY;
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.onEnd((event) => {
|
|
48
|
+
// Si se arrastró más de 50px o la velocidad es alta, cerramos
|
|
49
|
+
if (event.translationY > 50 || event.velocityY > 500) {
|
|
50
|
+
translateY.value = withTiming(150, {}, () => {
|
|
51
|
+
if (onDismiss) runOnJS(onDismiss)();
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
// Si no, regresa a su posición original
|
|
55
|
+
translateY.value = withSpring(0);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
60
|
+
transform: [{ translateY: translateY.value }],
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
if (!visible && translateY.value >= 100) return null;
|
|
25
64
|
|
|
26
65
|
return (
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
<GestureDetector gesture={gesture}>
|
|
67
|
+
<Animated.View
|
|
68
|
+
style={[
|
|
69
|
+
styles.snackbar,
|
|
70
|
+
animatedStyle,
|
|
71
|
+
{
|
|
72
|
+
backgroundColor: theme.surface.special.snackbar,
|
|
73
|
+
bottom: theme.space.lg,
|
|
74
|
+
padding: theme.space.md,
|
|
75
|
+
borderRadius: theme.radius.sm,
|
|
76
|
+
}
|
|
77
|
+
]}
|
|
78
|
+
>
|
|
79
|
+
<Text style={[
|
|
80
|
+
theme.typography.regular.sm,
|
|
81
|
+
{ color: theme.text.neutral.contrast, flex: 1 }
|
|
82
|
+
]}>
|
|
83
|
+
{message}
|
|
84
|
+
</Text>
|
|
46
85
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
</
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</
|
|
86
|
+
{action && (
|
|
87
|
+
<TouchableOpacity onPress={onDismiss} style={styles.actionButton}>
|
|
88
|
+
<Text style={[theme.typography.label, {
|
|
89
|
+
color: theme.text.neutral.contrast,
|
|
90
|
+
}]}>
|
|
91
|
+
{action}
|
|
92
|
+
</Text>
|
|
93
|
+
</TouchableOpacity>
|
|
94
|
+
)}
|
|
95
|
+
</Animated.View>
|
|
96
|
+
</GestureDetector>
|
|
58
97
|
);
|
|
59
98
|
};
|
|
60
99
|
|
|
@@ -67,11 +106,6 @@ const styles = StyleSheet.create({
|
|
|
67
106
|
flexDirection: 'row',
|
|
68
107
|
alignItems: 'center',
|
|
69
108
|
justifyContent: 'space-between',
|
|
70
|
-
elevation: 5,
|
|
71
|
-
shadowColor: '#000',
|
|
72
|
-
shadowOffset: { width: 0, height: 2 },
|
|
73
|
-
shadowOpacity: 0.25,
|
|
74
|
-
shadowRadius: 3.84,
|
|
75
109
|
zIndex: 1000,
|
|
76
110
|
},
|
|
77
111
|
actionButton: {
|
package/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
import 'react-native-gesture-handler';
|
|
3
|
+
import { registerRootComponent } from 'expo';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import App from './App';
|
|
6
|
+
registerRootComponent(App);
|
|
6
7
|
|
|
7
8
|
export {CDSBottomSheet} from './components/CDSBottomSheet';
|
|
8
9
|
export {CDSButton} from './components/CDSButton';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdslibrary",
|
|
3
3
|
"license": "0BSD",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.43",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Nat Viramontes",
|
|
7
7
|
"description": "A library of components for the CDS project",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"react": "*",
|
|
26
26
|
"react-dom": "*",
|
|
27
27
|
"react-native": "*",
|
|
28
|
-
"react-native-gesture-handler": "
|
|
28
|
+
"react-native-gesture-handler": "^2.30.0",
|
|
29
29
|
"react-native-reanimated": ">=3.0.0",
|
|
30
30
|
"react-native-safe-area-context": "*",
|
|
31
31
|
"react-native-screens": "*"
|
|
@@ -53,6 +53,7 @@ export const CDSsemanticColors = {
|
|
|
53
53
|
special: {
|
|
54
54
|
overlay: CDSprimitiveColors.overlay.light,
|
|
55
55
|
scroll: CDSprimitiveColors.neutral[400],
|
|
56
|
+
snackbar: CDSprimitiveColors.neutral[700],
|
|
56
57
|
tooltip: CDSprimitiveColors.neutral[500],
|
|
57
58
|
progress: CDSprimitiveColors.brand[600],
|
|
58
59
|
progressbarBg: CDSprimitiveColors.neutral[400],
|
|
@@ -164,6 +165,7 @@ export const CDSsemanticColors = {
|
|
|
164
165
|
special: {
|
|
165
166
|
overlay: CDSprimitiveColors.overlay.dark,
|
|
166
167
|
scroll: CDSprimitiveColors.neutral[400],
|
|
168
|
+
snackbar: CDSprimitiveColors.neutral[400],
|
|
167
169
|
tooltip: CDSprimitiveColors.neutral[500],
|
|
168
170
|
progress: CDSprimitiveColors.brand[600],
|
|
169
171
|
progressbarBg: CDSprimitiveColors.neutral[400],
|