cdslibrary 1.0.56 → 1.1.3
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/assets/animations/animation.json +1 -0
- package/assets/animations/animationLoaderWhite.json +1 -0
- package/components/CDSBottomSheet.jsx +148 -69
- package/components/CDSButton.jsx +10 -11
- package/components/CDSButtonGroup.jsx +52 -0
- package/components/CDSCardFeedback.jsx +121 -0
- package/components/CDSInput.jsx +37 -30
- package/components/CDSLoader.jsx +80 -0
- package/components/CDSNavBar.jsx +81 -0
- package/components/CDSOnboarding.jsx +0 -1
- package/components/CDSSelect.jsx +133 -0
- package/components/CDSSplashScreen.jsx +81 -0
- package/components/CDSSwitch.jsx +2 -2
- package/components/onboardingItem.jsx +3 -3
- package/context/CDSThemeContext.js +60 -27
- package/index.js +8 -6
- package/package.json +17 -9
- package/tokens/CDSprimitiveTokens.js +64 -6
- package/tokens/CDSsemanticColors.js +8 -7
- package/tokens/CDSsemanticTextStyles.js +186 -198
- package/assets/onboarding/image1.png +0 -0
- package/assets/onboarding/image1D.png +0 -0
- package/assets/onboarding/image2.png +0 -0
- package/assets/onboarding/image2D.png +0 -0
- package/assets/onboarding/image3.png +0 -0
- package/assets/onboarding/image3D.png +0 -0
- package/assets/onboarding/slides.js +0 -22
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { View, StyleSheet, Modal } from "react-native";
|
|
3
|
+
import LottieView from "lottie-react-native";
|
|
4
|
+
import Animated, {
|
|
5
|
+
useSharedValue,
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
withTiming,
|
|
8
|
+
withDelay, // 👈 Importamos withDelay
|
|
9
|
+
runOnJS
|
|
10
|
+
} from "react-native-reanimated";
|
|
11
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
12
|
+
|
|
13
|
+
export const CDSLoader = ({ visible = false }) => {
|
|
14
|
+
const { theme } = useTheme();
|
|
15
|
+
const [shouldRender, setShouldRender] = useState(visible);
|
|
16
|
+
const opacity = useSharedValue(0);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (visible) {
|
|
20
|
+
setShouldRender(true);
|
|
21
|
+
// Entrada rápida para que no se sienta lag al empezar
|
|
22
|
+
opacity.value = withTiming(1, { duration: 300 });
|
|
23
|
+
} else {
|
|
24
|
+
// 1. Espera 800ms antes de hacer nada (Sostenido)
|
|
25
|
+
// 2. Desvanece lentamente en 1200ms
|
|
26
|
+
opacity.value = withDelay(
|
|
27
|
+
1000,
|
|
28
|
+
withTiming(0, { duration: 1200 }, (isFinished) => {
|
|
29
|
+
if (isFinished) {
|
|
30
|
+
runOnJS(setShouldRender)(false);
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}, [visible]);
|
|
36
|
+
|
|
37
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
38
|
+
opacity: opacity.value,
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
if (!shouldRender && !visible) return null;
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Modal transparent visible={shouldRender} animationType="none">
|
|
45
|
+
<Animated.View style={[styles.overlay, animatedStyle,
|
|
46
|
+
{ backgroundColor: theme.overlay },]}>
|
|
47
|
+
<View
|
|
48
|
+
style={[
|
|
49
|
+
styles.loaderContainer,
|
|
50
|
+
]}
|
|
51
|
+
>
|
|
52
|
+
<LottieView
|
|
53
|
+
autoPlay
|
|
54
|
+
loop
|
|
55
|
+
source={require("../assets/animations/animationLoaderWhite.json")}
|
|
56
|
+
resizeMode="contain"
|
|
57
|
+
/>
|
|
58
|
+
</View>
|
|
59
|
+
</Animated.View>
|
|
60
|
+
</Modal>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const styles = StyleSheet.create({
|
|
65
|
+
overlay: {
|
|
66
|
+
height: '100%',
|
|
67
|
+
width: '100%',
|
|
68
|
+
justifyContent: "center",
|
|
69
|
+
alignItems: "center",
|
|
70
|
+
zIndex: 1000,
|
|
71
|
+
},
|
|
72
|
+
loaderContainer: {
|
|
73
|
+
padding: 20,
|
|
74
|
+
// O si usas fijos, asegúrate que sean mayores al estilo del Lottie
|
|
75
|
+
minWidth: 180,
|
|
76
|
+
minHeight: 180,
|
|
77
|
+
justifyContent: "center",
|
|
78
|
+
alignItems: "center",
|
|
79
|
+
},
|
|
80
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
import { View, Text, Dimensions, StyleSheet, Image, TouchableOpacity } from "react-native";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import { MaterialIcons } from "@expo/vector-icons";
|
|
6
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
7
|
+
import { getSemanticTextStyles } from "../tokens/CDSsemanticTextStyles";
|
|
8
|
+
import { useNavigation } from "@react-navigation/native";
|
|
9
|
+
|
|
10
|
+
const { height, width } = Dimensions.get("window");
|
|
11
|
+
|
|
12
|
+
const isMobile = width <= 878;
|
|
13
|
+
export const CDSNavBar = ({
|
|
14
|
+
|
|
15
|
+
type,
|
|
16
|
+
isExpanded,
|
|
17
|
+
hasClose,
|
|
18
|
+
title,
|
|
19
|
+
hasBack, }) => {
|
|
20
|
+
|
|
21
|
+
const { theme, isDarkMode } = useTheme();
|
|
22
|
+
|
|
23
|
+
const navigation = useNavigation();
|
|
24
|
+
|
|
25
|
+
const handleBackPress = () => {
|
|
26
|
+
if (hasBack) {
|
|
27
|
+
navigation.goBack();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleClosePress = () => {
|
|
32
|
+
if (hasClose) {
|
|
33
|
+
navigation.goBack();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={[styles.container, { backgroundColor: theme.surface.neutral.primary, borderColor: theme.outline.brand.primary }]}>
|
|
39
|
+
<TouchableOpacity onPress={handleBackPress}>
|
|
40
|
+
<MaterialIcons name="arrow-back-ios" size={theme.typography.icon.md} color={theme.text.neutral.primary} style={{ cursor: hasBack ? 'pointer' : 'default', opacity: hasBack ? 1 : 0 }} />
|
|
41
|
+
</TouchableOpacity>
|
|
42
|
+
{type === 'title' ? <Text style={[styles.title, theme.typography.semiBold.lg]}>{title || 'title'}</Text> : <Image
|
|
43
|
+
source={
|
|
44
|
+
isDarkMode
|
|
45
|
+
? require("../assets/images/logoMonteTW.png")
|
|
46
|
+
: require("../assets/images/logoMonte.png")
|
|
47
|
+
}
|
|
48
|
+
style={styles.logo}
|
|
49
|
+
resizeMode="contain"
|
|
50
|
+
/>}
|
|
51
|
+
<TouchableOpacity onPress={handleClosePress}>
|
|
52
|
+
<MaterialIcons name="close" size={theme.typography.icon.md} color={theme.text.neutral.primary} style={{ cursor: hasClose ? 'pointer' : 'default', opacity: hasClose ? 1 : 0 }} />
|
|
53
|
+
</TouchableOpacity>
|
|
54
|
+
</View>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const styles = StyleSheet.create({
|
|
59
|
+
container: {
|
|
60
|
+
width: '100%',
|
|
61
|
+
height: 56,
|
|
62
|
+
flexDirection: 'row',
|
|
63
|
+
alignItems: 'center',
|
|
64
|
+
justifyContent: 'space-between',
|
|
65
|
+
paddingHorizontal: 16,
|
|
66
|
+
borderBottomWidth: 1,
|
|
67
|
+
borderBottomColor: '#E0E0E0',
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
title: {
|
|
71
|
+
width: '100%',
|
|
72
|
+
textAlign: 'center',
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
logo: {
|
|
76
|
+
flex: 1,
|
|
77
|
+
height: '80%',
|
|
78
|
+
resizeMode: 'contain',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
});
|
|
@@ -3,7 +3,6 @@ import { Dimensions } from "react-native";
|
|
|
3
3
|
import {CDSBottomSheet} from "./CDSBottomSheet";
|
|
4
4
|
import {CDSCarousel} from "./CDSCarousel";
|
|
5
5
|
import { useTheme } from "../context/CDSThemeContext";
|
|
6
|
-
import { Onboarding } from "./Onboarding";
|
|
7
6
|
const { width } = Dimensions.get("window");
|
|
8
7
|
|
|
9
8
|
export const CDSOnboarding = () => {
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React, { useState, useRef } from "react";
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleSheet, FlatList, Animated } from "react-native";
|
|
3
|
+
import { MaterialIcons } from "@expo/vector-icons";
|
|
4
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
5
|
+
|
|
6
|
+
export const CDSSelect = ({ label, options = [], onSelect, placeholder = "Selecciona una opción" }) => {
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [selected, setSelected] = useState(null);
|
|
10
|
+
|
|
11
|
+
// Referencias para la animación
|
|
12
|
+
const animatedValue = useRef(new Animated.Value(0)).current;
|
|
13
|
+
|
|
14
|
+
const toggleDropdown = () => {
|
|
15
|
+
if (isOpen) {
|
|
16
|
+
// Animación de cierre
|
|
17
|
+
Animated.timing(animatedValue, {
|
|
18
|
+
toValue: 0,
|
|
19
|
+
duration: 200,
|
|
20
|
+
useNativeDriver: true,
|
|
21
|
+
}).start(() => setIsOpen(false));
|
|
22
|
+
} else {
|
|
23
|
+
setIsOpen(true);
|
|
24
|
+
// Animación de apertura
|
|
25
|
+
Animated.timing(animatedValue, {
|
|
26
|
+
toValue: 1,
|
|
27
|
+
duration: 300,
|
|
28
|
+
useNativeDriver: true,
|
|
29
|
+
}).start();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleSelect = (item) => {
|
|
34
|
+
setSelected(item);
|
|
35
|
+
toggleDropdown();
|
|
36
|
+
if (onSelect) onSelect(item.value);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Interpolación para el desplazamiento y la opacidad
|
|
40
|
+
const dropdownStyle = {
|
|
41
|
+
opacity: animatedValue,
|
|
42
|
+
transform: [
|
|
43
|
+
{
|
|
44
|
+
translateY: animatedValue.interpolate({
|
|
45
|
+
inputRange: [0, 1],
|
|
46
|
+
outputRange: [-10, 0], // Sube 10px mientras desaparece
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
return (
|
|
52
|
+
<View style={[styles.mainContainer, { zIndex: isOpen ? 1000 : 1, gap: theme.space.xs }]}>
|
|
53
|
+
{label && <Text style={[theme.typography.label, { color: theme.text.neutral.primary }]}>{label}</Text>}
|
|
54
|
+
|
|
55
|
+
<TouchableOpacity
|
|
56
|
+
activeOpacity={0.8}
|
|
57
|
+
style={[
|
|
58
|
+
styles.inputContainer,
|
|
59
|
+
theme.typography.inputText.value, { backgroundColor: theme.surface.neutral.primary, borderColor: selected ? theme.outline.neutral.tertiaryVariant : theme.outline.neutral.primary, borderRadius: theme.radius.sm, paddingHorizontal: theme.space.xs }
|
|
60
|
+
]}
|
|
61
|
+
onPress={toggleDropdown}
|
|
62
|
+
>
|
|
63
|
+
<Text style={selected ? theme.typography.inputText.value : theme.typography.inputText.placeholder}>
|
|
64
|
+
{selected ? selected.label : placeholder}
|
|
65
|
+
</Text>
|
|
66
|
+
<MaterialIcons
|
|
67
|
+
name={isOpen ? "expand-less" : "expand-more"}
|
|
68
|
+
size={theme.typography.icon.md}
|
|
69
|
+
color={theme.text.neutral.primary}
|
|
70
|
+
/>
|
|
71
|
+
</TouchableOpacity>
|
|
72
|
+
|
|
73
|
+
{isOpen && (
|
|
74
|
+
<Animated.View style={[
|
|
75
|
+
styles.dropdown,
|
|
76
|
+
dropdownStyle,
|
|
77
|
+
theme.shadows.lg,
|
|
78
|
+
{
|
|
79
|
+
backgroundColor: theme.surface.neutral.primary,
|
|
80
|
+
borderRadius: theme.radius.sm,
|
|
81
|
+
borderColor: theme.outline.neutral.primary,
|
|
82
|
+
elevation: 8,
|
|
83
|
+
maxHeight: 240,
|
|
84
|
+
}
|
|
85
|
+
]}>
|
|
86
|
+
<FlatList
|
|
87
|
+
data={options}
|
|
88
|
+
keyExtractor={(item) => item.value.toString()}
|
|
89
|
+
showsVerticalScrollIndicator={true}
|
|
90
|
+
persistentScrollbar={true}
|
|
91
|
+
renderItem={({ item }) => (
|
|
92
|
+
<TouchableOpacity
|
|
93
|
+
style={[styles.optionItem, { paddingHorizontal: theme.space.xs }]}
|
|
94
|
+
onPress={() => handleSelect(item)}
|
|
95
|
+
>
|
|
96
|
+
<Text style={[theme.typography.regular.sm, { color: theme.text.neutral.primary }]}>
|
|
97
|
+
{item.label}
|
|
98
|
+
</Text>
|
|
99
|
+
</TouchableOpacity>
|
|
100
|
+
)}
|
|
101
|
+
/>
|
|
102
|
+
</Animated.View>
|
|
103
|
+
)}
|
|
104
|
+
</View>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const styles = StyleSheet.create({
|
|
109
|
+
mainContainer: {
|
|
110
|
+
width: '100%',
|
|
111
|
+
},
|
|
112
|
+
inputContainer: {
|
|
113
|
+
height: 48,
|
|
114
|
+
borderWidth: 1,
|
|
115
|
+
flexDirection: 'row',
|
|
116
|
+
alignItems: 'center',
|
|
117
|
+
justifyContent: 'space-between',
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
dropdown: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
top: 90,
|
|
124
|
+
width: '100%',
|
|
125
|
+
borderWidth: 1,
|
|
126
|
+
overflow: 'hidden', // Necesario para que el contenido no se salga de los bordes redondeados
|
|
127
|
+
},
|
|
128
|
+
optionItem: {
|
|
129
|
+
height: 48, // 👈 Altura fija por ítem para controlar el límite de 5
|
|
130
|
+
paddingHorizontal: 18,
|
|
131
|
+
justifyContent: 'center'
|
|
132
|
+
}
|
|
133
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { View, StyleSheet } from "react-native";
|
|
2
|
+
import LottieView from "lottie-react-native";
|
|
3
|
+
import { useRef, useEffect } from "react";
|
|
4
|
+
import Animated, {
|
|
5
|
+
useSharedValue,
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
withTiming,
|
|
8
|
+
} from "react-native-reanimated";
|
|
9
|
+
import { useTheme } from "../context/CDSThemeContext";
|
|
10
|
+
|
|
11
|
+
export const CDSSplashScreen = ({ navigation, nextScreen }) => {
|
|
12
|
+
const { theme } = useTheme();
|
|
13
|
+
const animation = useRef(null);
|
|
14
|
+
const translateY = useSharedValue(0); // Definir un sharedValue para la posición vertical.
|
|
15
|
+
const size = useSharedValue(200); // Definir un sharedValue para el tamaño inicial.
|
|
16
|
+
const backgroundOpacity = useSharedValue(1);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Después de 6 segundos, mover la animación hacia arriba y cambiar el tamaño.
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
translateY.value = withTiming(-350, { duration: 1000 }); // Mover hacia arriba
|
|
21
|
+
size.value = withTiming(120, { duration: 1000 }); // Reducir el tamaño
|
|
22
|
+
backgroundOpacity.value = withTiming(0, { duration: 1000 });
|
|
23
|
+
// Esperar 1 segundo más antes de hacer el cambio de pantalla
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
navigation.replace(nextScreen);
|
|
26
|
+
}, 600);
|
|
27
|
+
}, 6000); // Esperar 6 segundos antes de la animación
|
|
28
|
+
}, [translateY, size]);
|
|
29
|
+
|
|
30
|
+
// Aplicar el estilo animado para la animación
|
|
31
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
32
|
+
return {
|
|
33
|
+
transform: [{ translateY: translateY.value }],
|
|
34
|
+
width: size.value, // Usar el tamaño animado
|
|
35
|
+
height: size.value, // Usar el tamaño animado
|
|
36
|
+
};
|
|
37
|
+
},[]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View style={styles.background}>
|
|
41
|
+
<View
|
|
42
|
+
style={[
|
|
43
|
+
styles.animationContainer,
|
|
44
|
+
{ backgroundColor: theme.surface.special.progress },
|
|
45
|
+
]}
|
|
46
|
+
>
|
|
47
|
+
<Animated.View
|
|
48
|
+
style={[
|
|
49
|
+
{ justifyContent: "center", alignItems: "center" },
|
|
50
|
+
animatedStyle,
|
|
51
|
+
]}
|
|
52
|
+
>
|
|
53
|
+
<LottieView
|
|
54
|
+
autoPlay
|
|
55
|
+
loop={false}
|
|
56
|
+
source={require("../assets/animations/animation.json")}
|
|
57
|
+
style={{ width: "100%", height: "100%" }} // Usar 100% del tamaño del contenedor
|
|
58
|
+
/>
|
|
59
|
+
</Animated.View>
|
|
60
|
+
</View>
|
|
61
|
+
</View>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const styles = StyleSheet.create({
|
|
66
|
+
background: {
|
|
67
|
+
flex: 1,
|
|
68
|
+
justifyContent: "center",
|
|
69
|
+
alignItems: "center",
|
|
70
|
+
backgroundColor: 'blue',
|
|
71
|
+
width: "100%",
|
|
72
|
+
},
|
|
73
|
+
animationContainer: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
width: "100%",
|
|
76
|
+
justifyContent: "center",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
gap: 16,
|
|
79
|
+
padding: 16,
|
|
80
|
+
},
|
|
81
|
+
});
|
package/components/CDSSwitch.jsx
CHANGED
|
@@ -5,14 +5,14 @@ import {getSemanticTextStyles} from "../tokens/CDSsemanticTextStyles";
|
|
|
5
5
|
|
|
6
6
|
export const CDSSwitch = ({ label }) => {
|
|
7
7
|
const { theme } = useTheme();
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
const [isEnabled, setIsEnabled] = useState(false);
|
|
10
10
|
|
|
11
11
|
const toggleSwitch = () => setIsEnabled((previousState) => !previousState);
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<View style={styles.container}>
|
|
15
|
-
<Text style={
|
|
15
|
+
<Text style={theme.typography.label}>
|
|
16
16
|
{label}
|
|
17
17
|
</Text>
|
|
18
18
|
<Switch onValueChange={toggleSwitch} value={isEnabled} />
|
|
@@ -4,13 +4,13 @@ import { useTheme } from "../context/CDSThemeContext";
|
|
|
4
4
|
export const OnboardingItem = ({ item, parentWidth }) => {
|
|
5
5
|
|
|
6
6
|
const { theme } = useTheme();
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
|
|
9
9
|
return (
|
|
10
10
|
<View style={[styles.container, {width: parentWidth}]}>
|
|
11
11
|
<View style={[styles.textContainer]}>
|
|
12
|
-
<Text style={
|
|
13
|
-
<Text style={
|
|
12
|
+
<Text style={theme.typography.bold.lg}>{item.title}</Text>
|
|
13
|
+
<Text style={theme.typography.regular.md}>{item.description}</Text>
|
|
14
14
|
</View>
|
|
15
15
|
<Image source={item.image} resizeMode="contain" style={[styles.image,]} />
|
|
16
16
|
</View>
|
|
@@ -1,52 +1,85 @@
|
|
|
1
1
|
import React, { createContext, useState, useContext, useEffect } from 'react';
|
|
2
|
-
import { Appearance, Platform } from 'react-native';
|
|
3
|
-
import {CDSsemanticColors} from '../tokens/CDSsemanticColors';
|
|
2
|
+
import { Appearance, Platform, Dimensions } from 'react-native';
|
|
4
3
|
|
|
4
|
+
// Importa tus tokens
|
|
5
|
+
import { CDSsemanticColors } from '../tokens/CDSsemanticColors';
|
|
6
|
+
import { getSemanticTextStyles } from '../tokens/CDSsemanticTextStyles';
|
|
7
|
+
import { CDSPrimitiveShadows, CDSPrimitiveSpacing, CDSPrimiviteRadius } from '../tokens/CDSprimitiveTokens';
|
|
5
8
|
|
|
6
9
|
const ThemeContext = createContext();
|
|
7
10
|
|
|
11
|
+
// Función para limpiar los objetos {mobile, desktop}
|
|
12
|
+
const resolveTokens = (primitives, isMobile) => {
|
|
13
|
+
const resolved = {};
|
|
14
|
+
for (const key in primitives) {
|
|
15
|
+
const value = primitives[key];
|
|
16
|
+
resolved[key] = (value && typeof value === 'object' && 'mobile' in value)
|
|
17
|
+
? (isMobile ? value.mobile : value.desktop)
|
|
18
|
+
: value;
|
|
19
|
+
}
|
|
20
|
+
return resolved;
|
|
21
|
+
};
|
|
22
|
+
|
|
8
23
|
export const CDSThemeProvider = ({ children }) => {
|
|
24
|
+
// 1. Definimos la función para obtener el tema inicial antes del estado
|
|
9
25
|
|
|
10
|
-
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const dimensionsSub = Dimensions.addEventListener('change', ({ window }) => {
|
|
28
|
+
setWindowWidth(window.width); // Esto es lo que dispara el re-render
|
|
29
|
+
});
|
|
30
|
+
return () => dimensionsSub.remove();
|
|
31
|
+
}, []);
|
|
32
|
+
const getInitialThemeMode = () => {
|
|
11
33
|
if (Platform.OS === 'web') {
|
|
12
34
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
13
35
|
}
|
|
14
36
|
return Appearance.getColorScheme() || 'light';
|
|
15
37
|
};
|
|
16
38
|
|
|
17
|
-
|
|
39
|
+
// 2. Estados principales
|
|
40
|
+
const [mode, setMode] = useState(getInitialThemeMode()); // Aquí es donde estaba el error
|
|
41
|
+
const [windowWidth, setWindowWidth] = useState(Dimensions.get('window').width);
|
|
42
|
+
|
|
43
|
+
const isMobile = windowWidth <= 768;
|
|
44
|
+
|
|
45
|
+
// 3. Efectos para cambios globales
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const themeSub = Appearance.addChangeListener(({ colorScheme }) => {
|
|
48
|
+
setMode(colorScheme || 'light');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const dimensionsSub = Dimensions.addEventListener('change', ({ window }) => {
|
|
52
|
+
setWindowWidth(window.width);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
themeSub.remove();
|
|
57
|
+
dimensionsSub.remove();
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
18
60
|
|
|
19
61
|
const toggleTheme = () => {
|
|
20
|
-
|
|
62
|
+
setMode(prev => (prev === 'light' ? 'dark' : 'light'));
|
|
21
63
|
};
|
|
22
64
|
|
|
23
|
-
|
|
65
|
+
// 4. Construcción del objeto final (IMPORTANTE: colors primero)
|
|
66
|
+
const colors = CDSsemanticColors[mode];
|
|
24
67
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
mediaQuery.removeEventListener('change', handleChange);
|
|
35
|
-
};
|
|
36
|
-
} else {
|
|
37
|
-
const subscription = Appearance.addChangeListener(({ colorScheme }) => {
|
|
38
|
-
setTheme(colorScheme);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return () => subscription.remove();
|
|
42
|
-
}
|
|
43
|
-
}, []);
|
|
68
|
+
const themeValue = {
|
|
69
|
+
...colors,
|
|
70
|
+
mode: mode,
|
|
71
|
+
isMobile,
|
|
72
|
+
space: resolveTokens(CDSPrimitiveSpacing, isMobile),
|
|
73
|
+
radius: CDSPrimiviteRadius,
|
|
74
|
+
typography: getSemanticTextStyles(colors, isMobile),
|
|
75
|
+
shadows: CDSPrimitiveShadows(mode),
|
|
76
|
+
};
|
|
44
77
|
|
|
45
78
|
return (
|
|
46
|
-
<ThemeContext.Provider value={{ theme:
|
|
79
|
+
<ThemeContext.Provider value={{ theme: themeValue, toggleTheme, isDarkMode: mode === 'dark' }}>
|
|
47
80
|
{children}
|
|
48
81
|
</ThemeContext.Provider>
|
|
49
82
|
);
|
|
50
83
|
};
|
|
51
84
|
|
|
52
|
-
export const useTheme = () => useContext(ThemeContext);
|
|
85
|
+
export const useTheme = () => useContext(ThemeContext);
|
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
import { registerRootComponent } from 'expo';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import App from './App';
|
|
5
|
+
registerRootComponent(App);
|
|
6
6
|
|
|
7
7
|
export {CDSBottomSheet} from './components/CDSBottomSheet';
|
|
8
8
|
export {CDSButton} from './components/CDSButton';
|
|
@@ -11,8 +11,10 @@ export {CDSCarousel} from './components/CDSCarousel';
|
|
|
11
11
|
export {CDSInput} from './components/CDSInput';
|
|
12
12
|
export {CDSOnboarding} from './components/CDSOnboarding';
|
|
13
13
|
export {CDSSwitch} from './components/CDSSwitch';
|
|
14
|
-
|
|
14
|
+
export {CDSNavBar} from './components/CDSNavBar';
|
|
15
|
+
export {CDSCardFeedback} from './components/CDSCardFeedback';
|
|
16
|
+
export {CDSSplashScreen} from './components/CDSSplashScreen';
|
|
17
|
+
export {CDSButtonGroup} from './components/CDSButtonGroup';
|
|
18
|
+
export {CDSSelect} from './components/CDSSelect';
|
|
15
19
|
|
|
16
20
|
export {CDSThemeProvider, useTheme} from './context/CDSThemeContext';
|
|
17
|
-
export {getSemanticTextStyles} from './tokens/CDSsemanticTextStyles';
|
|
18
|
-
export {CDSsemanticColors} from './tokens/CDSsemanticColors';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdslibrary",
|
|
3
3
|
"license": "0BSD",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.3",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Nat Viramontes",
|
|
7
7
|
"description": "A library of components for the CDS project",
|
|
@@ -13,17 +13,25 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@expo-google-fonts/inter": "^0.2.3",
|
|
16
|
-
"@expo/metro-runtime": "~
|
|
17
|
-
"@expo/vector-icons": "^
|
|
16
|
+
"@expo/metro-runtime": "~6.1.2",
|
|
17
|
+
"@expo/vector-icons": "^15.0.3",
|
|
18
|
+
"@lottiefiles/dotlottie-react": "^0.13.5",
|
|
19
|
+
"@react-navigation/native": "^7.1.28",
|
|
18
20
|
"cli": "^1.0.1",
|
|
19
|
-
"expo": "
|
|
20
|
-
"expo-
|
|
21
|
-
"
|
|
22
|
-
"react-native": "
|
|
23
|
-
"react
|
|
21
|
+
"expo": "^54.0.31",
|
|
22
|
+
"expo-linear-gradient": "~15.0.8",
|
|
23
|
+
"expo-status-bar": "~3.0.9",
|
|
24
|
+
"lottie-react-native": "^7.3.5",
|
|
25
|
+
"react": "19.1.0",
|
|
26
|
+
"react-dom": "^19.1.0",
|
|
27
|
+
"react-native": "0.81.5",
|
|
28
|
+
"react-native-reanimated": "^4.2.1",
|
|
29
|
+
"react-native-safe-area-context": "~5.6.0",
|
|
30
|
+
"react-native-screens": "~4.16.0",
|
|
31
|
+
"react-native-web": "^0.21.0"
|
|
24
32
|
},
|
|
25
33
|
"devDependencies": {
|
|
26
|
-
"@babel/core": "^7.
|
|
34
|
+
"@babel/core": "^7.28.6"
|
|
27
35
|
},
|
|
28
36
|
"private": false
|
|
29
37
|
}
|