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