cdslibrary 1.2.84 → 1.2.86

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.
@@ -73,17 +73,24 @@ const bottomSheetRender = ({
73
73
 
74
74
  useEffect(() => {
75
75
  if (isVisible) {
76
+ // Animación de Entrada
76
77
  translation.value = withTiming(0, {
77
78
  duration: 300,
78
79
  easing: Easing.out(Easing.exp),
79
80
  });
80
81
  opacity.value = withTiming(1, { duration: 200 });
82
+ } else {
83
+ // Animación de Salida (ESTO ES LO QUE FALTABA)
84
+ translation.value = withTiming(startPos, { duration: 300 });
85
+ opacity.value = withTiming(0, { duration: 300 });
81
86
  }
82
- }, [isVisible]);
87
+ }, [isVisible, startPos]); // Asegúrate de incluir startPos
83
88
 
84
- const animatedStyle = useAnimatedStyle(() => {
89
+ const animatedStyle = useAnimatedStyle(() => {
85
90
  return {
86
91
  opacity: opacity.value,
92
+ // Ocultamos el layout completamente si terminó de salir
93
+ display: (translation.value >= startPos && !isVisible) ? 'none' : 'flex',
87
94
  transform: [
88
95
  isMobile
89
96
  ? { translateY: translation.value }
@@ -94,15 +101,24 @@ const bottomSheetRender = ({
94
101
 
95
102
  const backdropStyle = useAnimatedStyle(() => {
96
103
  const currentY = translation.value;
97
- const opacityVal = interpolate(currentY, [0, height], [1, 0], Extrapolation.CLAMP);
104
+ // Si está en la posición inicial (startPos), la opacidad es 0
105
+ const opacityVal = interpolate(
106
+ currentY,
107
+ [0, startPos],
108
+ [1, 0],
109
+ Extrapolation.CLAMP
110
+ );
111
+
98
112
  return {
99
113
  opacity: opacityVal,
114
+ display: opacityVal <= 0 ? 'none' : 'flex',
100
115
  };
101
116
  });
102
117
 
103
118
  return (
104
119
  <>
105
120
  <Animated.View
121
+ pointerEvents={isVisible ? "auto" : "none"} // Evita clics fantasma
106
122
  style={[
107
123
  styles.overlay,
108
124
  { backgroundColor: theme.surface.special.overlay },
@@ -111,7 +127,6 @@ const bottomSheetRender = ({
111
127
  >
112
128
  <Pressable onPress={() => runOnJS(handleClose)()} style={{ flex: 1 }} />
113
129
  </Animated.View>
114
-
115
130
  <Animated.View
116
131
  style={[
117
132
  isMobile ? styles.container.typeBottomSheet : styles.container.typeDrawer,
@@ -213,17 +228,20 @@ const styles = StyleSheet.create({
213
228
  left: 0,
214
229
  right: 0,
215
230
  zIndex: 99,
216
- ...Platform.select({web:{maxHeight: '95%'}})
231
+ ...Platform.select({ web: { maxHeight: '95%' } })
217
232
  },
218
233
  typeDrawer: {
219
234
  position: "absolute",
220
235
  right: 0,
221
- top: 0,
222
236
  bottom: 0,
223
237
  width: 600,
238
+ maxHeight: height * .95, // Evita que se salga de la pantalla si hay mucho texto
224
239
  zIndex: 99,
225
240
  ...Platform.select({
226
- web: { boxShadow: '-10px 0px 15px rgba(0,0,0,0.1)' }
241
+ web: {
242
+ boxShadow: '-10px 0px 15px rgba(0,0,0,0.1)',
243
+ height: 'auto', // En web forzamos que sea auto
244
+ }
227
245
  })
228
246
  },
229
247
  },
@@ -232,7 +250,7 @@ const styles = StyleSheet.create({
232
250
  width: '100%',
233
251
  },
234
252
  scrollArea: {
235
- width: '100%', // Quitamos el flex: 1 de aquí para que sea dinámico
253
+ width: '100%',
236
254
  },
237
255
  scrollContent: {
238
256
  gap: 16,
@@ -80,6 +80,7 @@ const animatedLayout = {
80
80
  backgroundColor: currentStyle.bg,
81
81
  borderColor: currentStyle.border,
82
82
  borderRadius: theme.radius.md,
83
+ borderWidth: 1,
83
84
  paddingHorizontal: theme.space.md,
84
85
  gap: theme.space.sm,
85
86
  overflow: 'hidden', // Evita que el texto se salga mientras se achica
@@ -5,65 +5,84 @@ import Animated, {
5
5
  useSharedValue,
6
6
  withSequence,
7
7
  withTiming,
8
+ withDelay,
8
9
  interpolateColor
9
10
  } from "react-native-reanimated";
10
11
  import { useTheme } from "../context/CDSThemeContext";
11
12
 
13
+ const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
14
+
12
15
  export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeText, animationTrigger, returnKeyType, onFocus }) => {
13
16
  const { theme } = useTheme();
14
17
  const [isFocused, setIsFocused] = useState(false);
15
18
 
16
19
  const flashValue = useSharedValue(0);
20
+ const textHighlight = useSharedValue(0);
17
21
  const isInternalChange = useRef(false);
18
22
 
23
+ const isReadOnly = type === 'readOnly';
24
+
25
+ // --- Colores de seguridad ---
26
+ const colorBase = theme?.text?.neutral?.primary
27
+ const colorReadOnlyText = theme?.text?.neutral?.secondary
28
+ const colorFocus = theme?.surface?.special?.progress
29
+ const colorTertiary = theme?.outline?.neutral?.tertiaryVariant
30
+ const colorPrimaryOutline = theme?.outline?.neutral?.primary
31
+
19
32
  useEffect(() => {
20
- if (!isInternalChange.current) {
21
- flashValue.value = withSequence(
22
- withTiming(1, { duration: 200 }),
33
+ // ELIMINAMOS la restricción de !isReadOnly para que se anime siempre
34
+ if (!isInternalChange.current && value) {
35
+ flashValue.value = withDelay(400, withSequence(
36
+ withTiming(1, { duration: 400 }),
37
+ withTiming(0, { duration: 600 })
38
+ ));
39
+
40
+ textHighlight.value = withSequence(
41
+ withTiming(1, { duration: 400 }),
23
42
  withTiming(0, { duration: 600 })
24
43
  );
25
44
  }
26
45
  isInternalChange.current = false;
27
- }, [value, animationTrigger]);
28
-
29
- const handleTextChange = (inputText) => {
30
- isInternalChange.current = true;
31
-
32
- if (keyboard === "numeric" || keyboard === "decimal-pad") {
33
- let cleaned = inputText.replace(',', '.').replace(/[^0-9.]/g, "");
34
- const parts = cleaned.split('.');
35
- if (parts.length > 2) cleaned = parts[0] + '.' + parts.slice(1).join('');
36
- onChangeText && onChangeText(cleaned);
37
- } else {
38
- onChangeText && onChangeText(inputText);
39
- }
40
- };
46
+ }, [value, animationTrigger]); // Quitamos isReadOnly de las dependencias para evitar disparos extra
41
47
 
42
48
  const animatedBoxStyle = useAnimatedStyle(() => {
43
49
  const borderColor = interpolateColor(
44
50
  flashValue.value,
45
51
  [0, 1],
46
52
  [
47
- isFocused ? theme.outline.neutral.focus : value ? theme.outline.neutral.tertiaryVariant : theme.outline.neutral.primary,
48
- theme.outline.neutral.focus
53
+ isFocused ? colorFocus : value ? colorTertiary : colorPrimaryOutline,
54
+ colorFocus
49
55
  ]
50
56
  );
51
57
 
52
58
  return {
53
- borderColor: borderColor,
54
- // Quitamos el scale momentáneamente para asegurar que el layout no brinque
55
- // transform: [{ scale: 1 + flashValue.value * 0.01 }],
56
- borderWidth: 1 + (flashValue.value * 1),
59
+ borderColor,
60
+ borderWidth: 1 + (flashValue.value * 2),
61
+ transform: [{ scale: 1 + (flashValue.value * 0.06) }]
57
62
  };
58
63
  });
59
64
 
65
+ const animatedTextStyle = useAnimatedStyle(() => {
66
+ // Definimos el color inicial según si es readOnly o no
67
+ const startColor = isReadOnly ? colorReadOnlyText : colorBase;
68
+
69
+ return {
70
+ color: interpolateColor(
71
+ textHighlight.value,
72
+ [0, 1],
73
+ [startColor, colorFocus] // El color de "brillo" sigue siendo el de foco
74
+ ),
75
+ letterSpacing: textHighlight.value * 1,
76
+ opacity: isReadOnly ? 0.85 + (textHighlight.value * 0.3) : 0.8 + (textHighlight.value * 0.2),
77
+ };
78
+ });
79
+
80
+ if (!theme) return null;
81
+
60
82
  return (
61
83
  <View style={styles.container}>
62
84
  {label && (
63
- <Text style={[
64
- theme.typography.label,
65
- { color: theme.text.neutral.primary, marginBottom: theme.space.xs }
66
- ]}>
85
+ <Text style={[theme.typography.label, { color: colorBase, marginBottom: theme.space?.xs || 4 }]}>
67
86
  {label}
68
87
  </Text>
69
88
  )}
@@ -72,35 +91,34 @@ export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeTe
72
91
  styles.wrapper,
73
92
  animatedBoxStyle,
74
93
  {
75
- backgroundColor: type === 'readOnly' ? theme.surface.neutral.primaryVariant : theme.surface.neutral.primary,
76
- borderRadius: theme.radius.sm,
94
+ backgroundColor: isReadOnly ? theme.surface.neutral.primaryVariant : theme.surface.neutral.primary,
95
+ borderRadius: theme.radius?.sm || 8,
77
96
  }
78
97
  ]}>
79
- <TextInput
98
+ <AnimatedTextInput
80
99
  style={[
81
100
  styles.textBox,
82
- theme.typography.inputText.value,
101
+ theme.typography.inputText?.value,
102
+ animatedTextStyle,
83
103
  {
84
- paddingHorizontal: theme.space.sm,
85
- color: type === 'readOnly' ? theme.text.neutral.secondary : theme.text.neutral.primary,
86
- // Fix para web:
87
- ...Platform.select({
88
- web: { outlineStyle: 'none' }
89
- })
104
+ paddingHorizontal: theme.space?.sm || 12,
105
+ fontWeight: '600',
106
+ ...Platform.select({ web: { outlineStyle: 'none' } })
90
107
  },
91
108
  ]}
92
109
  placeholder={placeholder}
93
110
  placeholderTextColor={theme.text.neutral.placeholder}
94
- keyboardType={keyboard === "numeric" ? (Platform.OS === 'ios' ? 'decimal-pad' : 'numeric') : keyboard}
95
- onChangeText={handleTextChange}
111
+ keyboardType={keyboard}
112
+ onChangeText={(txt) => {
113
+ isInternalChange.current = true;
114
+ onChangeText && onChangeText(txt);
115
+ }}
96
116
  value={value}
97
- editable={type !== 'readOnly'}
117
+ editable={!isReadOnly}
98
118
  secureTextEntry={type === "password"}
99
- onFocus={() => { setIsFocused(true); onFocus }}
119
+ onFocus={() => { setIsFocused(true); onFocus && onFocus(); }}
100
120
  onBlur={() => setIsFocused(false)}
101
121
  underlineColorAndroid="transparent"
102
- returnKeyType={returnKeyType}
103
- dataSet={{ lpignore: "true" }}
104
122
  />
105
123
  </Animated.View>
106
124
  </View>
@@ -108,20 +126,14 @@ export const CDSInput = ({ label, type, keyboard, placeholder, value, onChangeTe
108
126
  };
109
127
 
110
128
  const styles = StyleSheet.create({
111
- container: {
112
- width: "100%",
113
- alignSelf: 'stretch',
114
- },
129
+ container: { width: "100%", alignSelf: 'stretch' },
115
130
  wrapper: {
116
131
  width: '100%',
117
132
  height: 48,
118
- flexDirection: 'row', // Asegura que el TextInput interno tenga un eje claro
133
+ flexDirection: 'row',
119
134
  alignItems: 'center',
120
135
  borderWidth: 1,
136
+ overflow: 'hidden'
121
137
  },
122
- textBox: {
123
- flex: 1, // Esto es lo más importante: ocupa todo el espacio sobrante
124
- height: '100%',
125
- width: '100%',
126
- },
138
+ textBox: { flex: 1, height: '100%', width: '100%' },
127
139
  });
@@ -9,7 +9,7 @@ export const CDSSwitch = ({ label, onValueChange, value }) => {
9
9
  <View style={[styles.container, { }]}>
10
10
  {label && (
11
11
  <Text style={[
12
- theme.typography.label,
12
+ theme.typography.regular.md,
13
13
  { color: theme.text.neutral.primary, flex: 1, marginRight: theme.space.md }
14
14
  ]}>
15
15
  {label}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cdslibrary",
3
3
  "license": "0BSD",
4
- "version": "1.2.84",
4
+ "version": "1.2.86",
5
5
  "main": "index.js",
6
6
  "author": "Nat Viramontes",
7
7
  "description": "A library of components for the CDS project",