cdslibrary 1.2.10 → 1.2.12

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.
@@ -1,15 +1,11 @@
1
- import React, { useEffect, useRef, useState } from "react";
2
- import { View, Text, Animated, Dimensions, StyleSheet, Pressable, Platform } from "react-native";
1
+ import React, { useEffect, useState } from "react";
2
+ import { View, Text, Animated, Dimensions, StyleSheet, Pressable, Platform, ScrollView } from "react-native";
3
3
  import { CDSButton } from "./CDSButton";
4
-
5
4
  import { MaterialIcons } from "@expo/vector-icons";
6
5
  import { useTheme } from "../context/CDSThemeContext";
7
- import { ScrollView } from "react-native-web";
8
6
  import { LinearGradient } from 'expo-linear-gradient';
9
7
 
10
-
11
8
  const { height, width } = Dimensions.get("window");
12
-
13
9
  const isMobile = width <= 878;
14
10
 
15
11
  export const CDSBottomSheet = ({
@@ -24,89 +20,99 @@ export const CDSBottomSheet = ({
24
20
  secondaryButtonLabel = "Cancelar",
25
21
  onFinish,
26
22
  }) => {
27
-
28
- const handleLayout = (event) => {
29
- const { height: layoutHeight } = event.nativeEvent.layout;
30
- setChildHeight(layoutHeight);
31
- };
32
-
33
23
  const { theme } = useTheme();
34
- const [childHeight, setChildHeight] = useState(0);
35
24
  const [modalVisible, setModalVisible] = useState(isVisible);
36
25
  const [modalOpacity] = useState(new Animated.Value(0));
37
- const [slidePosition] = useState(new Animated.Value(height));
38
-
26
+ const [slidePosition] = useState(new Animated.Value(isMobile ? height : width));
39
27
 
40
-
41
- useEffect(() => {
42
- const targetValue = isMobile ? height : width; // Valor fuera de pantalla
28
+ // Función unificada para cerrar con animación
29
+ const handleClose = () => {
30
+ const targetValue = isMobile ? height : width;
43
31
 
44
32
  Animated.parallel([
45
33
  Animated.timing(modalOpacity, {
46
- toValue: modalVisible ? 1 : 0,
47
- duration: 400,
34
+ toValue: 0,
35
+ duration: 350,
48
36
  useNativeDriver: false,
49
37
  }),
50
38
  Animated.timing(slidePosition, {
51
- toValue: modalVisible ? 0 : targetValue, // 0 es visible, targetValue es oculto
52
- duration: 400,
39
+ toValue: targetValue,
40
+ duration: 350,
53
41
  useNativeDriver: false,
54
42
  }),
55
- ]).start();
56
- }, [modalVisible, isMobile]); // Añadimos isMobile a las dependencias
43
+ ]).start(() => {
44
+ // Importante: onFinish se ejecuta SOLO cuando la animación termina
45
+ if (onFinish) onFinish();
46
+ setModalVisible(false);
47
+ });
48
+ };
49
+
50
+ useEffect(() => {
51
+ if (modalVisible) {
52
+ Animated.parallel([
53
+ Animated.timing(modalOpacity, {
54
+ toValue: 1,
55
+ duration: 400,
56
+ useNativeDriver: false,
57
+ }),
58
+ Animated.timing(slidePosition, {
59
+ toValue: 0,
60
+ duration: 400,
61
+ useNativeDriver: false,
62
+ }),
63
+ ]).start();
64
+ }
65
+ }, [modalVisible]);
66
+
57
67
  return (
58
68
  <>
59
69
  <Animated.View
60
- onLayout={handleLayout}
61
70
  style={[
62
71
  isMobile ? styles.container.typeBottomSheet : styles.container.typeDrawer,
63
72
  {
64
73
  opacity: modalOpacity,
65
74
  transform: [
66
- isMobile
67
- ? { translateY: slidePosition } // Sube en móvil
68
- : { translateX: slidePosition } // Entra lateral en desktop
75
+ isMobile ? { translateY: slidePosition } : { translateX: slidePosition }
69
76
  ],
70
- backgroundColor: theme.surface.neutral.primary, paddingHorizontal: theme.space.sm,
77
+ backgroundColor: theme.surface.neutral.primary,
78
+ paddingHorizontal: theme.space.sm,
71
79
  paddingTop: theme.space.xl,
72
80
  gap: theme.space.sm,
73
- }, isMobile ? [styles.container.typeBottomSheet, {
74
- borderTopLeftRadius: theme.radius.lg,
75
- borderTopRightRadius: theme.radius.lg,
76
- }] : [styles.container.typeDrawer, {
77
- borderBottomLeftRadius: theme.radius.lg, borderTopLeftRadius: theme.radius.lg, paddingBottom: theme.space.md,
78
- },
79
- ]]}
81
+ ...(isMobile ? {
82
+ borderTopLeftRadius: theme.radius.lg,
83
+ borderTopRightRadius: theme.radius.lg,
84
+ } : {
85
+ borderBottomLeftRadius: theme.radius.lg,
86
+ borderTopLeftRadius: theme.radius.lg,
87
+ paddingBottom: theme.space.md,
88
+ })
89
+ }
90
+ ]}
80
91
  >
81
-
82
92
  {hasClose && (
83
93
  <MaterialIcons
84
- name={"close"}
94
+ name="close"
85
95
  size={theme.typography.icon.lg}
86
96
  color={theme.text.neutral.primary}
87
- onPress={() => {
88
- onFinish();
89
- setModalVisible(false);
90
- }}
91
- style={{ position: "absolute", right: theme.space.sm, top: theme.space.sm }}
97
+ onPress={handleClose}
98
+ style={{ position: "absolute", right: theme.space.sm, top: theme.space.sm, zIndex: 10 }}
92
99
  />
93
100
  )}
94
- <Text style={theme.typography.bold.lg}>{title}</Text>
101
+
102
+ {!!title && <Text style={theme.typography.bold.lg}>{title}</Text>}
103
+
95
104
  <View style={styles.scrollWrapper}>
96
105
  <ScrollView
97
106
  style={styles.scrollArea}
98
- contentContainerStyle={[styles.scrollContent, {
99
- flexGrow: 0,
100
- paddingBottom: theme.space.md
101
- }]}
107
+ contentContainerStyle={[styles.scrollContent, { paddingBottom: theme.space.md }]}
102
108
  showsVerticalScrollIndicator={true}
103
- persistentScrollbar={true}
104
- indicatorStyle={theme.name === 'dark' ? 'white' : 'black'}
105
109
  >
106
- {description && (
107
- <Text style={[theme.typography.regular.md, { marginBottom: theme.space.md }]}>{description}</Text>
110
+ {!!description && (
111
+ <Text style={[theme.typography.regular.md, { marginBottom: theme.space.md }]}>
112
+ {description}
113
+ </Text>
108
114
  )}
109
- {customSlot && <View style={styles.customSlot}>{customSlot}</View>}
115
+ {customSlot}
110
116
  </ScrollView>
111
117
  <LinearGradient
112
118
  colors={['transparent', theme.surface.neutral.primary]}
@@ -114,27 +120,25 @@ export const CDSBottomSheet = ({
114
120
  pointerEvents="none"
115
121
  />
116
122
  </View>
123
+
117
124
  {type !== "informative" && (
118
125
  <View style={isMobile ? styles.actionsContainer.typeBottomSheet : styles.actionsContainer.typeDrawer}>
119
126
  <CDSButton
120
127
  label={primaryButtonLabel}
121
128
  onPress={() => {
122
- primaryButtonOnPress(),
123
- setModalVisible(!modalVisible)
124
- }
125
- }
129
+ if (primaryButtonOnPress) primaryButtonOnPress();
130
+ handleClose();
131
+ }}
126
132
  />
127
133
  <CDSButton
128
134
  label={secondaryButtonLabel}
129
135
  type="ghost"
130
- onPress={() => {
131
- onFinish();
132
- setModalVisible(false);
133
- }}
136
+ onPress={handleClose}
134
137
  />
135
138
  </View>
136
139
  )}
137
140
  </Animated.View>
141
+
138
142
  <Animated.View
139
143
  style={[
140
144
  styles.overlay,
@@ -144,103 +148,74 @@ export const CDSBottomSheet = ({
144
148
  },
145
149
  ]}
146
150
  >
147
- <Pressable onPress={() => setModalVisible(false)} style={{ flex: 1 }} />
151
+ <Pressable onPress={handleClose} style={{ flex: 1 }} />
148
152
  </Animated.View>
149
153
  </>
150
154
  );
151
- }
155
+ };
152
156
 
153
157
  const styles = StyleSheet.create({
154
158
  overlay: {
155
159
  position: "absolute",
156
160
  top: 0,
157
161
  left: 0,
158
- width: "100%",
159
- height: "100%"
162
+ right: 0,
163
+ bottom: 0,
164
+ zIndex: 98,
160
165
  },
161
-
162
166
  container: {
163
167
  typeBottomSheet: {
164
168
  maxHeight: '90%',
165
- flex: 1,
166
- justifyContent: "flex-end",
167
- alignItems: "center",
168
- zIndex: 99,
169
169
  width: "100%",
170
170
  position: "absolute",
171
171
  bottom: 0,
172
+ left: 0,
173
+ right: 0,
174
+ zIndex: 99,
172
175
  },
173
176
  typeDrawer: {
174
- position: "absolute", // Clave para el Drawer
175
- right: 0, // Anclado a la derecha
177
+ position: "absolute",
178
+ right: 0,
176
179
  top: 0,
177
180
  bottom: 0,
178
- justifyContent: "center",
179
- zIndex: 99,
180
181
  width: 600,
182
+ zIndex: 99,
183
+ ...Platform.select({
184
+ web: { boxShadow: '-10px 0px 15px rgba(0,0,0,0.1)' }
185
+ })
181
186
  },
182
187
  },
183
-
184
188
  scrollWrapper: {
185
- flex: 1, // Ocupa todo el espacio vertical disponible
186
- position: 'relative', // Para que el gradiente se posicione absolutamente dentro de él
189
+ flex: 1,
190
+ position: 'relative',
187
191
  width: '100%',
188
192
  },
189
193
  scrollArea: {
190
- flexShrink: 1,
191
- flexGrow: 1,
194
+ flex: 1,
192
195
  width: '100%',
193
- paddingBottom: 20,
194
196
  },
195
-
196
197
  scrollContent: {
197
- paddingBottom: 20, // Aire al final del contenido
198
198
  gap: 16,
199
199
  },
200
-
201
200
  fadeGradient: {
202
201
  position: 'absolute',
203
202
  bottom: 0,
204
203
  left: 0,
205
204
  right: 0,
206
- height: 60, // Ajusta la altura del gradiente según tu diseño
207
- },
208
-
209
- infoContainer: {
210
- typeBottomSheet: {
211
- width: "100%",
212
- zIndex: 100,
213
- pointerEvents: "all",
214
- },
215
- typeDrawer: {
216
- flex: 1, // Ocupa todo el alto disponible en el Drawer
217
- width: "100%",
218
- zIndex: 100,
219
- pointerEvents: "all",
220
- // Opcional: una sombra elegante para Desktop
221
- ...Platform.select({
222
- web: { boxShadow: '-10px 0px 15px rgba(0,0,0,0.2)' }
223
- })
224
- },
205
+ height: 40,
225
206
  },
226
207
  actionsContainer: {
227
208
  typeBottomSheet: {
228
- flex: "row",
209
+ flexDirection: "row",
229
210
  width: "100%",
230
211
  gap: 8,
212
+ paddingBottom: 20,
231
213
  },
232
214
  typeDrawer: {
233
- marginTop: 'auto',
234
215
  flexDirection: "row-reverse",
235
216
  width: "100%",
236
217
  gap: 8,
218
+ marginTop: 'auto',
237
219
  },
238
220
  },
239
-
240
- customSlot: {
241
- width: '100%',
242
- height: 'auto',
243
- },
244
-
245
- });
246
-
221
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cdslibrary",
3
3
  "license": "0BSD",
4
- "version": "1.2.10",
4
+ "version": "1.2.12",
5
5
  "main": "index.js",
6
6
  "author": "Nat Viramontes",
7
7
  "description": "A library of components for the CDS project",