cdslibrary 1.0.0

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.
@@ -0,0 +1,8 @@
1
+ > Why do I have a folder named ".expo" in my project?
2
+ The ".expo" folder is created when an Expo project is started using "expo start" command.
3
+ > What do the files contain?
4
+ - "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
5
+ - "settings.json": contains the server configuration that is used to serve the application manifest.
6
+ > Should I commit the ".expo" folder?
7
+ No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
8
+ Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
@@ -0,0 +1,3 @@
1
+ {
2
+ "devices": []
3
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "expoServerPort": 19000,
3
+ "packagerPort": 19000
4
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "hostType": "lan",
3
+ "lanType": "ip",
4
+ "dev": true,
5
+ "minify": false,
6
+ "urlRandomness": null,
7
+ "https": false,
8
+ "scheme": null,
9
+ "devClient": false
10
+ }
package/app.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "expo": {
3
+ "name": "CDSLibrary",
4
+ "slug": "CDSLibrary",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "icon": "./assets/icon.png",
8
+ "userInterfaceStyle": "auto",
9
+ "newArchEnabled": true,
10
+ "ios": {
11
+ "supportsTablet": true
12
+ },
13
+ "android": {
14
+ "adaptiveIcon": {
15
+ "foregroundImage": "./assets/adaptive-icon.png",
16
+ "backgroundColor": "#ffffff"
17
+ }
18
+ },
19
+ "web": {
20
+ "favicon": "./assets/favicon.png"
21
+ }
22
+ }
23
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,22 @@
1
+ // slides.js
2
+ export const getSlides = (isDarkMode) => [
3
+ {
4
+ id: 'slide1',
5
+ title: "Tus boletas en un solo lugar",
6
+ description: "Conoce el estado general de tus boletas y dales seguimiento desde la aplicación.",
7
+ image: isDarkMode ? require("./image1D.png") : require("./image1.png")
8
+ },
9
+ {
10
+ id: 'slide2',
11
+ title: "Realiza tus pagos",
12
+ description: "Puedes refrendar o pagar tus desempeños con diferentes métodos de pago.",
13
+ image: isDarkMode ? require("./image2D.png") : require("./image2.png")
14
+ },
15
+ {
16
+ id: 'slide3',
17
+ title: "Tu eliges cuánto pagar",
18
+ description: "Puedes elegir la cantidad que deseas pagar en tus boletas.",
19
+ // Revisa que el uso de imágenes sea correcto según el modo:
20
+ image: isDarkMode ? require("./image3D.png") : require("./image3.png")
21
+ }
22
+ ];
Binary file
@@ -0,0 +1,163 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import { View, Text, Animated, Dimensions, StyleSheet, Pressable, Platform } from "react-native";
3
+ import { CDSButton } from "./CDSButton";
4
+
5
+ import { MaterialIcons } from "@expo/vector-icons";
6
+ import { useTheme } from "../context/CDSThemeContext";
7
+ import { getSemanticTextStyles } from "../tokens/CDSsemanticTextStyles";
8
+
9
+ const { height, width } = Dimensions.get("window");
10
+
11
+ const isMobile = width <= 878;
12
+
13
+ export const CDSBottomSheet = ({
14
+ type,
15
+ isVisible,
16
+ hasClose,
17
+ title,
18
+ description ,
19
+ customSlot,
20
+ primaryButtonLabel,
21
+ primaryButtonOnPress,
22
+ secondaryButtonLabel = "Cancelar",
23
+ onFinish,
24
+ }) => {
25
+
26
+ const [childHeight, setChildHeight] = useState(0);
27
+ const handleLayout = (event) => {
28
+ const { width } = event.nativeEvent.layout;
29
+ console.log("Ancho:", width, "Alto:", height);
30
+ setChildHeight(width); // Guardamos el ancho en el estado
31
+ };
32
+
33
+ const { theme } = useTheme();
34
+ const textStyles = getSemanticTextStyles(theme);
35
+
36
+ const [modalVisible, setModalVisible] = useState(isVisible);
37
+ const [modalOpacity] = useState(new Animated.Value(0));
38
+ const [slidePosition] = useState(new Animated.Value(height));
39
+
40
+ useEffect(() => {
41
+ Animated.parallel([
42
+ Animated.timing(modalOpacity, {
43
+ toValue: modalVisible ? 1 : 0,
44
+ duration: 500,
45
+ useNativeDriver: false,
46
+ }),
47
+ Animated.timing(slidePosition, {
48
+ toValue: modalVisible ? 0 : height,
49
+ duration: modalVisible ? 500 : 800,
50
+ useNativeDriver: false,
51
+ }),
52
+ ]).start();
53
+ }, [modalVisible]);
54
+
55
+ return (
56
+ <>
57
+ <Animated.View onLayout={handleLayout}
58
+ style={[isMobile ? styles.centeredView.typeBottomSheet : styles.centeredView.typeModal,
59
+ {opacity: modalOpacity, transform: isMobile && [{ translateY: slidePosition }] },
60
+ ]}
61
+ >
62
+ <View style={[isMobile ? styles.container.typeBottomSheet : styles.container.typeModal, { backgroundColor: theme.surface.neutral.primary } ]}>
63
+ {hasClose && (
64
+ <MaterialIcons
65
+ name={"close"}
66
+ size={textStyles.icon.fontSize}
67
+ color={"red"}
68
+ style={{ position: "absolute", right: 16, top: 16 }}
69
+ />
70
+ )}
71
+ {title && <Text style={textStyles.bold.lg}>{title}</Text>}
72
+ {description && (
73
+ <Text style={textStyles.regular.md}>{description}</Text>
74
+ )}
75
+ {customSlot && <View style={{ height: childHeight,}}>{customSlot}</View>}
76
+ {type !== "informative" && (
77
+ <View style={styles.actionsContainer}>
78
+ <CDSButton
79
+ label={primaryButtonLabel}
80
+ onPress={
81
+ onFinish
82
+ ? () => settypeMVisible(!modalVisible)
83
+ : primaryButtonOnPress
84
+ }
85
+ />
86
+ <CDSButton
87
+ label={secondaryButtonLabel}
88
+ type="ghost"
89
+ onPress={() => setModalVisible(!modalVisible)}
90
+ />
91
+ </View>
92
+ )}
93
+ </View>
94
+ </Animated.View>
95
+ <Animated.View
96
+ style={[
97
+ styles.overlay,
98
+ {
99
+ opacity: modalOpacity,
100
+ backgroundColor: theme.surface.special.overlay,
101
+ },
102
+ ]}
103
+ >
104
+ <Pressable onPress={() => setModalVisible(false)} style={{ flex: 1 }} />
105
+ </Animated.View>
106
+ </>
107
+ );
108
+ }
109
+
110
+ const styles = StyleSheet.create({
111
+ overlay: {
112
+ position: "absolute",
113
+ top: 0,
114
+ left: 0,
115
+ width: "110%",
116
+ height: "104.4%",
117
+ zIndex: 9,
118
+ },
119
+
120
+ centeredView: {
121
+ typeBottomSheet: {
122
+ flex: 1,
123
+ justifyContent: "flex-end",
124
+ alignItems: "center",
125
+ zIndex: 99,
126
+ pointerEvents: "none",
127
+ width: "100%",
128
+ },
129
+ typeModal: {
130
+ justifyContent: "center",
131
+ alignItems: "center",
132
+ zIndex: 99,
133
+ },
134
+ },
135
+ container: {
136
+ typeBottomSheet: {
137
+ width: "100%",
138
+ borderTopLeftRadius: 16,
139
+ borderTopRightRadius: 16,
140
+ paddingHorizontal: 16,
141
+ paddingVertical: 24,
142
+ gap: 16,
143
+ zIndex: 100,
144
+ pointerEvents: "all",
145
+ },
146
+ typeModal: {
147
+ width: 600,
148
+ borderRadius: 16,
149
+ paddingHorizontal: 16,
150
+ paddingVertical: 24,
151
+ gap: 16,
152
+ zIndex: 100,
153
+ pointerEvents: "all",
154
+ },
155
+ },
156
+ actionsContainer: {
157
+ flex: "row",
158
+ width: "100%",
159
+ gap: 8,
160
+ },
161
+
162
+ });
163
+
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import { Text, StyleSheet, TouchableOpacity } from "react-native";
3
+ import { Dimensions, Platform } from "react-native";
4
+ import { MaterialIcons } from "@expo/vector-icons";
5
+ import { useTheme } from "../context/CDSThemeContext";
6
+ import {getSemanticTextStyles} from "../tokens/CDSsemanticTextStyles";
7
+
8
+ const { width } = Dimensions.get("window");
9
+ const isMobile = width <= 878 && Platform.OS !== "web";
10
+
11
+ export const CDSButton = ({
12
+ label,
13
+ type = "primary",
14
+ size,
15
+ onPress,
16
+ icon,
17
+ flexend,
18
+ }) => {
19
+ const { theme } = useTheme();
20
+ const textStyles = getSemanticTextStyles(theme);
21
+
22
+ const backgroundColor =
23
+ type === "disabled"
24
+ ? theme.surface.action.disabled
25
+ : type === "secondary" || type === "ghost" || type === "link"
26
+ ? "transparent"
27
+ : theme.surface.action.primary;
28
+
29
+ const textColor =
30
+ type === "secondary" || type === "ghost" || type === "link"
31
+ ? theme.text.neutral.primary
32
+ : type === "disabled"
33
+ ? theme.text.neutral.disabled
34
+ : theme.text.neutral.contrast;
35
+
36
+ return (
37
+ <TouchableOpacity
38
+ onPress={type !== "disabled" ? onPress : null}
39
+ activeOpacity={0.7}
40
+ style={[
41
+ styles.container,
42
+ { backgroundColor },
43
+ flexend && { justifyContent: "flex-end", paddingHorizontal: 0 },
44
+ isMobile && type !== "icon"
45
+ ? { width: "100%" }
46
+ : { paddingHorizontal: 12 },
47
+ type === "secondary" && {
48
+ borderColor: theme.outline.action.primary,
49
+ borderWidth: 1,
50
+ },
51
+ type === 'link' && {
52
+ paddingHorizontal: 0,
53
+ paddingVertical: 0,
54
+ width: 'auto',
55
+ }
56
+ ]}
57
+ >
58
+ {type !== "icon" && (
59
+ <Text
60
+ style={[
61
+ type === "link"
62
+ ? size === "small"
63
+ ? textStyles.link.small
64
+ : textStyles.link.regular
65
+ : textStyles.buttonText,
66
+ { color: textColor },
67
+ ]}
68
+ >
69
+ {label}
70
+ </Text>
71
+ )}
72
+ {icon && (
73
+ <MaterialIcons
74
+ name={icon}
75
+ size={textStyles.icon.fontSize}
76
+ color={textColor}
77
+ />
78
+ )}
79
+ </TouchableOpacity>
80
+ );
81
+ };
82
+
83
+ const styles = StyleSheet.create({
84
+ container: {
85
+ minWidth: 343,
86
+ flexDirection: "row",
87
+ alignItems: "center",
88
+ justifyContent: "center",
89
+ paddingVertical: 12,
90
+ paddingHorizontal: 24,
91
+ borderRadius: 100,
92
+ gap: 8,
93
+ },
94
+ });
95
+
@@ -0,0 +1,60 @@
1
+ import React, { useState } from "react";
2
+ import { View, Image, ScrollView, Dimensions } from "react-native";
3
+ import { useTheme } from "../context/CDSThemeContext";
4
+ // const { width } = Dimensions.get("window");
5
+
6
+
7
+
8
+ export const CDSCarousel = ({ activeIndex, scrollViewRef, onScroll, images }) => {
9
+ const { theme } = useTheme();
10
+ const [scrollViewWidth, setScrollViewWidth] = useState(0);
11
+
12
+ const onLayout = (event) => {
13
+ const { width } = event.nativeEvent.layout;
14
+ setScrollViewWidth(width); // Establece el ancho del ScrollView
15
+ };
16
+
17
+ return (
18
+ <View style={{ alignItems: "center", marginTop: 20 }}>
19
+ <ScrollView
20
+ ref={scrollViewRef}
21
+ horizontal
22
+ pagingEnabled
23
+ showsHorizontalScrollIndicator={false}
24
+ onScroll={onScroll}
25
+ scrollEventThrottle={16}
26
+ style={{ width: '100%', }}
27
+ contentContainerStyle={{ width: scrollViewWidth * images.length, alignItems: 'center' }
28
+ }
29
+ onLayout={onLayout}
30
+ >
31
+ {images.map((image, index) => (
32
+ <View key={index} style={{ width: scrollViewWidth, justifyContent: 'center', alignItems: 'center', backgroundColor: 'red' }}>
33
+ <Image
34
+ source={image}
35
+ style={{
36
+ height: 353,
37
+ }}
38
+ resizeMode={"cover"}
39
+ />
40
+ </View>
41
+ ))}
42
+ </ScrollView>
43
+ <View style={{ flexDirection: "row", marginTop: 10 }}>
44
+ {images.map((_, index) => (
45
+ <View
46
+ key={index}
47
+ style={{
48
+ width: activeIndex === index ? 14 : 10,
49
+ height: 10,
50
+ borderRadius: 5,
51
+ backgroundColor: activeIndex === index ? theme.surface.special.progress : theme.surface.special.progressbarBg,
52
+ marginHorizontal: 5,
53
+ }}
54
+ />
55
+ ))}
56
+ </View>
57
+ </View>
58
+ );
59
+ };
60
+
@@ -0,0 +1,56 @@
1
+ import React from "react";
2
+ import { View, Animated, StyleSheet, Dimensions } from "react-native";
3
+
4
+ const { width } = Dimensions.get("window");
5
+
6
+ const PaginationDots = ({ data, scrollX, itemWidth }) => {
7
+ const dotWidth = 10; // Ancho de cada dot
8
+ const spacing = 5; // Espaciado entre dots
9
+
10
+ // Calcular la posición del dot activo
11
+ const translateX = scrollX.interpolate({
12
+ inputRange: data.map((_, index) => index * itemWidth),
13
+ outputRange: data.map((_, index) => index * (dotWidth + spacing)),
14
+ extrapolate: "clamp",
15
+ });
16
+
17
+ return (
18
+ <View style={styles.container}>
19
+ {/* Dots estáticos */}
20
+ {data.map((_, index) => (
21
+ <View key={index} style={styles.dot} />
22
+ ))}
23
+
24
+ {/* Dot animado que se mueve */}
25
+ <Animated.View
26
+ style={[styles.activeDot, { transform: [{ translateX }] }]}
27
+ />
28
+ </View>
29
+ );
30
+ };
31
+
32
+ const styles = StyleSheet.create({
33
+ container: {
34
+ flexDirection: "row",
35
+ marginTop: 10,
36
+ justifyContent: "center",
37
+ position: "relative",
38
+ },
39
+ dot: {
40
+ width: 10,
41
+ height: 10,
42
+ borderRadius: 5,
43
+ backgroundColor: "gray",
44
+ marginHorizontal: 5,
45
+ },
46
+ activeDot: {
47
+ width: 10,
48
+ height: 10,
49
+ borderRadius: 5,
50
+ backgroundColor: "black",
51
+ position: "absolute",
52
+ left: 0,
53
+ },
54
+ });
55
+
56
+ export default PaginationDots;
@@ -0,0 +1,54 @@
1
+ import { StyleSheet, Text, TextInput, View } from "react-native";
2
+ import { useTheme } from "../context/CDSThemeContext";
3
+ import getSemanticTextStyles from "../tokens/CDSsemanticTextStyles";
4
+ import { useState } from "react";
5
+
6
+ export default function StyledInput({ label, type, keyboard, placeholder }) {
7
+ const { theme } = useTheme();
8
+ const textStyles = getSemanticTextStyles(theme);
9
+ const [text, setText] = useState("");
10
+
11
+ return (
12
+ <View style={[styles.container]}>
13
+ <Text
14
+ style={[
15
+ textStyles.label,
16
+ ]}
17
+ >
18
+ {label}
19
+ </Text>
20
+ {text === "" && (
21
+ <Text style={[styles.fakePlaceholder, textStyles.inputText.placeholder]}>
22
+ {placeholder}
23
+ </Text>
24
+ )}
25
+ <TextInput
26
+ style={[styles.textBox, textStyles.inputText.value, {backgroundColor:theme.surface.neutral.primary, borderColor: theme.outline.neutral.primary }]}
27
+ keyboardType={keyboard}
28
+ secureTextEntry={type === "password" ? true : false}
29
+ onChangeText={setText}
30
+ value={text}
31
+ />
32
+ </View>
33
+ );
34
+ }
35
+
36
+ const styles = StyleSheet.create({
37
+ container: {
38
+ width: "100%",
39
+ gap: 8,
40
+ },
41
+
42
+ fakePlaceholder: {
43
+ position: "absolute",
44
+ zIndex: 1,
45
+ left: 14,
46
+ top: 40,
47
+ },
48
+
49
+ textBox: {
50
+ padding: 12,
51
+ borderRadius: 8,
52
+ borderWidth: 1,
53
+ },
54
+ });
@@ -0,0 +1,70 @@
1
+ import React, { act, useRef, useState } from "react";
2
+ import { Dimensions } from "react-native";
3
+ import {CDSBottomSheet} from "./CDSBottomSheet";
4
+ import {CDSCarousel} from "./CDSCarousel";
5
+ import { useTheme } from "../context/CDSThemeContext";
6
+ import { Onboarding } from "./Onboarding";
7
+ const { width } = Dimensions.get("window");
8
+
9
+ export const CDSOnboarding = () => {
10
+ const { isDarkMode } = useTheme();
11
+ const scrollViewRef = useRef(null);
12
+ const [activeIndex, setActiveIndex] = useState(0);
13
+ const [isLastSlide, setIsLastSlide] = useState(false);
14
+
15
+ const images = !isDarkMode
16
+ ? [
17
+ require("../assets/onboarding/image1.png"),
18
+ require("../assets/onboarding/image2.png"),
19
+ require("../assets/onboarding/image3.png"),
20
+ ]
21
+ : [
22
+ require("../assets/onboarding/image1D.png"),
23
+ require("../assets/onboarding/image2D.png"),
24
+ require("../assets/onboarding/image3D.png"),
25
+ ];
26
+
27
+ const handleScroll = (event) => {
28
+ const index = Math.round(event.nativeEvent.contentOffset.x / width);
29
+ setActiveIndex(index);
30
+ setIsLastSlide(index === images.length - 1);
31
+ };
32
+
33
+ const handleNext = () =>
34
+ !isLastSlide &&
35
+ scrollViewRef.current.scrollTo({
36
+ x: (activeIndex + 1) * width,
37
+ animated: true,
38
+ });
39
+
40
+ return (
41
+ <CDSBottomSheet
42
+ isVisible
43
+ customSlot={
44
+ <CDSCarousel
45
+ activeIndex={activeIndex}
46
+ scrollViewRef={scrollViewRef}
47
+ onScroll={handleScroll}
48
+ images={images}
49
+ />
50
+ }
51
+ title={
52
+ (activeIndex === 0 && "Tus boletas en un solo lugar") ||
53
+ (activeIndex === 1 && "Realiza tus pagos") ||
54
+ (activeIndex === 2 && "Tu eliges cuánto pagar")
55
+ }
56
+ description={
57
+ (activeIndex === 0 &&
58
+ "Conoce el estado general de tus boletas y dales seguimiento desde la aplicación.") ||
59
+ (activeIndex === 1 &&
60
+ "Puedes refrendar o pagar tus desempeños con diferentes métodos de pago.") ||
61
+ (activeIndex === 2 &&
62
+ "Con “Pagos libres” elige la cantidad, reduce los intereses y abona a capital desde el primer día.")
63
+ }
64
+ primaryButtonLabel={!isLastSlide ? "Siguiente" : "Finalizar"}
65
+ primaryButtonOnPress={handleNext}
66
+ onFinish={isLastSlide && true}
67
+ secondaryButtonLabel="Ahora no"
68
+ />
69
+ );
70
+ };
@@ -0,0 +1,29 @@
1
+ import React, { useState } from "react";
2
+ import { View, Text, Switch, StyleSheet } from "react-native";
3
+ import { useTheme } from "../context/CDSThemeContext";
4
+ import getSemanticTextStyles from "../tokens/CDSsemanticTextStyles";
5
+
6
+ export default function CDSSwitch({ label }) {
7
+ const { theme } = useTheme();
8
+ const textStyles = getSemanticTextStyles(theme);
9
+ const [isEnabled, setIsEnabled] = useState(false);
10
+
11
+ const toggleSwitch = () => setIsEnabled((previousState) => !previousState);
12
+
13
+ return (
14
+ <View style={styles.container}>
15
+ <Text style={textStyles.label}>
16
+ {label}
17
+ </Text>
18
+ <Switch onValueChange={toggleSwitch} value={isEnabled} />
19
+ </View>
20
+ );
21
+ }
22
+
23
+ const styles = StyleSheet.create({
24
+ container: {
25
+ flexDirection: "row",
26
+ justifyContent: "space-between",
27
+ alignItems: "center",
28
+ },
29
+ });
@@ -0,0 +1,14 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Platform } from 'react-native';
3
+
4
+ const CustomSlotDebug = ({ customSlot, isVisible }) => {
5
+ useEffect(() => {
6
+ console.log('Platform:', Platform.OS);
7
+ console.log('Custom Slot:', customSlot);
8
+ console.log('Is Visible:', isVisible);
9
+ }, [customSlot, isVisible]);
10
+
11
+ return <>{customSlot}</>;
12
+ };
13
+
14
+ export default CustomSlotDebug;