aport-tools 4.5.0 → 4.6.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.
Files changed (39) hide show
  1. package/package.json +17 -34
  2. package/src/cards/Card.tsx +129 -0
  3. package/src/cards/index.ts +1 -0
  4. package/src/components/Button.tsx +180 -0
  5. package/src/fonts/Text.tsx +137 -0
  6. package/{dist/fonts/index.d.ts → src/fonts/index.ts} +1 -0
  7. package/src/forms/ErrorList.tsx +47 -0
  8. package/src/forms/FORMDOC.md +87 -0
  9. package/{dist/forms/Form.d.ts → src/forms/Form.tsx} +2 -0
  10. package/src/forms/FormContext.tsx +248 -0
  11. package/src/forms/Input.tsx +174 -0
  12. package/src/forms/InputAttach.tsx +184 -0
  13. package/src/forms/InputCheck.tsx +169 -0
  14. package/src/forms/InputList.tsx +304 -0
  15. package/src/forms/Label.tsx +26 -0
  16. package/src/forms/Stepper.tsx +289 -0
  17. package/src/forms/TextArea.tsx +91 -0
  18. package/{dist/forms/index.d.ts → src/forms/index.ts} +4 -2
  19. package/src/index.ts +6 -0
  20. package/dist/cards/Card.d.ts +0 -57
  21. package/dist/cards/index.d.ts +0 -1
  22. package/dist/components/Button.d.ts +0 -52
  23. package/dist/defaults/reanimatedWrapper.d.ts +0 -2
  24. package/dist/fonts/Text.d.ts +0 -64
  25. package/dist/forms/ErrorList.d.ts +0 -6
  26. package/dist/forms/FormContext.d.ts +0 -132
  27. package/dist/forms/Input.d.ts +0 -43
  28. package/dist/forms/InputAttach.d.ts +0 -16
  29. package/dist/forms/InputCheck.d.ts +0 -19
  30. package/dist/forms/InputList.d.ts +0 -93
  31. package/dist/forms/Label.d.ts +0 -7
  32. package/dist/forms/Stepper.d.ts +0 -54
  33. package/dist/forms/TextArea.d.ts +0 -13
  34. package/dist/index.d.ts +0 -4
  35. package/dist/index.esm.js +0 -1493
  36. package/dist/index.esm.js.map +0 -1
  37. package/dist/index.js +0 -1526
  38. package/dist/index.js.map +0 -1
  39. /package/{dist/buttons/index.d.ts → src/buttons/index.ts} +0 -0
package/package.json CHANGED
@@ -1,28 +1,25 @@
1
1
  {
2
2
  "name": "aport-tools",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "Aport mobile Tools with modern and minimalistic design",
5
- "main": "dist/index.js",
6
- "module": "dist/index.esm.js",
7
- "react-native": "dist/index.js",
8
- "source": "src/index.ts",
9
- "types": "dist/index.d.ts",
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
10
7
  "type": "module",
11
8
  "exports": {
12
- ".": "./dist/index.js",
13
- "./buttons": "./dist/buttons/index.js",
14
- "./theme": "./dist/theme/index.js",
15
- "./cards": "./dist/cards/index.js",
16
- "./fonts": "./dist/fonts/index.js",
17
- "./forms": "./dist/forms/index.js"
9
+ ".": {
10
+ "import": "./src/index.ts",
11
+ "types": "./src/index.ts"
12
+ },
13
+ "./*": "./src/*"
18
14
  },
19
15
  "files": [
20
- "dist"
16
+ "src"
21
17
  ],
22
18
  "scripts": {
23
- "build": "rollup -c rollup.config.mjs",
19
+ "build": "tsc --noEmit",
24
20
  "prepare": "npm run build",
25
- "test": "echo \"Error: no test specified\" && exit 1"
21
+ "test": "echo \"Error: no test specified\" && exit 1",
22
+ "clean": "rm -rf dist .turbo node_modules/.cache .parcel-cache .expo .next .output .yalc .npm _site"
26
23
  },
27
24
  "keywords": [
28
25
  "react-native",
@@ -36,30 +33,16 @@
36
33
  "author": "EvansGxz",
37
34
  "license": "ISC",
38
35
  "devDependencies": {
39
- "@babel/core": "^7.25.2",
40
- "@babel/preset-env": "^7.25.4",
41
- "@babel/preset-react": "^7.24.7",
42
- "@babel/preset-typescript": "^7.24.7",
43
- "@rollup/plugin-babel": "^6.0.4",
44
- "@rollup/plugin-commonjs": "^28.0.0",
45
- "@rollup/plugin-json": "^6.1.0",
46
- "@rollup/plugin-node-resolve": "^15.3.0",
47
- "@rollup/plugin-typescript": "^12.1.0",
48
- "@types/react": "^18.3.10",
49
- "@types/react-native": "^0.73.0",
50
- "react-native-reanimated": "^3.10.1",
51
- "rollup": "^4.22.5",
52
- "rollup-plugin-peer-deps-external": "^2.2.4",
36
+ "@types/react": "19.0.0",
37
+ "@types/react-native": "^0.79.0",
53
38
  "typescript": "^5.6.2"
54
39
  },
55
40
  "peerDependencies": {
56
41
  "@react-native-async-storage/async-storage": "^1.23.1",
57
42
  "aport-themes": "^1.0.6",
58
43
  "expo-image-picker": "^16.0.2",
59
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
60
- "react-native": ">=0.60",
61
- "react-native-reanimated": "^3.6.1"
62
- },
63
- "dependencies": {
44
+ "react": "19.0.0",
45
+ "react-native": "0.79.0",
46
+ "react-native-reanimated": "^3.17.5"
64
47
  }
65
48
  }
@@ -0,0 +1,129 @@
1
+ // src/cards/Card.tsx
2
+
3
+ import { ThemeContext } from 'aport-themes';
4
+ import React, { useContext } from 'react';
5
+ import {
6
+ View,
7
+ StyleSheet,
8
+ StyleProp,
9
+ ViewStyle,
10
+ Platform,
11
+ TouchableOpacity,
12
+ GestureResponderEvent,
13
+ } from 'react-native';
14
+
15
+ /**
16
+ * Interface for the props that the Card component accepts.
17
+ */
18
+ interface CardProps {
19
+ /**
20
+ * Content to be rendered inside the Card.
21
+ */
22
+ children: React.ReactNode;
23
+
24
+ /**
25
+ * Style to be applied to the Card container.
26
+ */
27
+ style?: StyleProp<ViewStyle>;
28
+
29
+ /**
30
+ * Function to call when the Card is pressed.
31
+ */
32
+ onPress?: (event: GestureResponderEvent) => void;
33
+
34
+ /**
35
+ * Whether the Card is pressable. Defaults to false.
36
+ */
37
+ pressable?: boolean;
38
+
39
+ /**
40
+ * Border radius of the Card. Defaults to 12.
41
+ */
42
+ borderRadius?: number;
43
+
44
+ /**
45
+ * Elevation of the Card (Android only).
46
+ */
47
+ elevation?: number;
48
+
49
+ /**
50
+ * Shadow properties for iOS.
51
+ */
52
+ shadowProps?: {
53
+ shadowColor?: string;
54
+ shadowOffset?: { width: number; height: number };
55
+ shadowOpacity?: number;
56
+ shadowRadius?: number;
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Card component that adapts its styles based on the current theme.
62
+ * Supports dynamic styling, shadows, and press animations.
63
+ *
64
+ * @param children - The content to be displayed inside the Card.
65
+ * @param style - Additional styles to apply to the Card.
66
+ * @param onPress - Function to execute when the Card is pressed.
67
+ * @param pressable - Determines if the Card is pressable. Defaults to false.
68
+ * @param borderRadius - Border radius of the Card. Defaults to 12.
69
+ * @param elevation - Elevation for Android shadow. Overrides default.
70
+ * @param shadowProps - Custom shadow properties for iOS. Overrides defaults.
71
+ */
72
+ export const Card: React.FC<CardProps> = ({
73
+ children,
74
+ style,
75
+ onPress,
76
+ pressable = false,
77
+ borderRadius = 12,
78
+ elevation = 4,
79
+ shadowProps = {},
80
+ }) => {
81
+ const { theme } = useContext(ThemeContext);
82
+ const { colors } = theme;
83
+
84
+ // Animation state for pressable effect
85
+ // Default shadow styles (improved platform-specific handling)
86
+ const defaultShadow = Platform.select({
87
+ ios: {
88
+ shadowColor: shadowProps?.shadowColor || colors.text.hex, // Defaulting to theme text color
89
+ shadowOffset: shadowProps?.shadowOffset || { width: 0, height: 2 },
90
+ shadowOpacity: shadowProps?.shadowOpacity || 0.1,
91
+ shadowRadius: shadowProps?.shadowRadius || 4,
92
+ },
93
+ android: {
94
+ elevation: elevation, // Only applies to Android
95
+ },
96
+ });
97
+
98
+ const cardStyles = [
99
+ styles.container,
100
+ { borderRadius, backgroundColor: colors.background.hex },
101
+ defaultShadow, // Dynamic shadows based on platform
102
+ style, // External styles
103
+ ];
104
+
105
+ return pressable ? (
106
+ <TouchableOpacity
107
+ activeOpacity={0.8}
108
+ onPress={onPress}
109
+
110
+ style={cardStyles}
111
+ >
112
+
113
+ {children}
114
+ </TouchableOpacity>
115
+ ) : (
116
+ <View style={cardStyles}>
117
+ {children}
118
+ </View>
119
+ );
120
+ };
121
+
122
+ const styles = StyleSheet.create({
123
+ container: {
124
+ padding: 16,
125
+ borderRadius: 12,
126
+ // Shadows handled dynamically with platform logic
127
+ },
128
+ });
129
+
@@ -0,0 +1 @@
1
+ export { Card } from './Card';
@@ -0,0 +1,180 @@
1
+ // src/components/Button.tsx
2
+
3
+ import React, { useMemo, useContext } from 'react';
4
+ import { Text, ViewStyle, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native';
5
+ import { useFormContext } from '../forms';
6
+ import { ThemeColors, ThemeContext } from 'aport-themes';
7
+
8
+ /**
9
+ * Interface for the props that the Button component accepts.
10
+ */
11
+ interface ButtonProps {
12
+ /**
13
+ * If true, the button is disabled and not pressable.
14
+ */
15
+ disabled?: boolean;
16
+
17
+ /**
18
+ * If true, the button expands to full width of its container.
19
+ */
20
+ isFullWidth?: boolean;
21
+
22
+ /**
23
+ * Text content of the button.
24
+ */
25
+ children?: string;
26
+
27
+ /**
28
+ * Function to call when the button is pressed.
29
+ */
30
+ onPress?: () => void;
31
+
32
+ /**
33
+ * If true, the button has rounded corners.
34
+ */
35
+ rounded?: boolean;
36
+
37
+ /**
38
+ * Custom border radius value. Overrides the `rounded` prop if provided.
39
+ */
40
+ borderRadius?: number;
41
+
42
+ /**
43
+ * Specifies the button type for styling. Can be 'submit', 'button', or 'cancel'.
44
+ */
45
+ type?: 'submit' | 'button' | 'cancel';
46
+
47
+ /**
48
+ * If true, a loading spinner is shown and the button is disabled.
49
+ */
50
+ loading?: boolean;
51
+ }
52
+
53
+ /**
54
+ * Determines the styles based on the button type and whether it is disabled.
55
+ *
56
+ * @param type - The type of the button ('submit', 'button', 'cancel').
57
+ * @param disabled - Whether the button is disabled.
58
+ * @param themeColors - The theme colors.
59
+ * @returns The computed style for the button.
60
+ */
61
+ function typeStyles(
62
+ type?: string,
63
+ disabled?: boolean,
64
+ themeColors?: ThemeColors
65
+ ): ViewStyle {
66
+ switch (type) {
67
+ case 'submit':
68
+ return {
69
+ backgroundColor: `rgba(${themeColors?.primary.rgb.r}, ${themeColors?.primary.rgb.g}, ${themeColors?.primary.rgb.b}, ${
70
+ disabled ? 0.5 : 1
71
+ })`,
72
+ borderWidth: 2,
73
+ borderColor: themeColors?.primary.hex,
74
+ };
75
+ case 'button':
76
+ return {
77
+ backgroundColor: themeColors?.primary.hex,
78
+ borderColor: themeColors?.secondary.hex,
79
+ opacity: disabled ? 0.5 : 1,
80
+ borderWidth: 2,
81
+ };
82
+ case 'cancel':
83
+ return {
84
+ backgroundColor: themeColors?.background.hex,
85
+ borderWidth: 0,
86
+ };
87
+ default:
88
+ return {};
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Button component that adapts its styles based on the current theme.
94
+ * Supports dynamic styling, full-width option, rounded corners, and different types.
95
+ *
96
+ * @param disabled - If true, the button is disabled and not pressable.
97
+ * @param isFullWidth - If true, the button expands to full width of its container.
98
+ * @param children - Text content of the button.
99
+ * @param onPress - Function to call when the button is pressed.
100
+ * @param rounded - If true, the button has rounded corners.
101
+ * @param borderRadius - Custom border radius value. Overrides the `rounded` prop if provided.
102
+ * @param type - Specifies the button type for styling ('submit', 'button', 'cancel').
103
+ */
104
+ export const Button: React.FC<ButtonProps> = ({
105
+ children,
106
+ disabled = false,
107
+ type = 'button',
108
+ rounded = true,
109
+ borderRadius = 30,
110
+ isFullWidth = false,
111
+ loading = false,
112
+ onPress,
113
+ }) => {
114
+ const { theme } = useContext(ThemeContext);
115
+ const { colors } = theme;
116
+
117
+ const computedStyles = useMemo(() => {
118
+ return StyleSheet.flatten([
119
+ styles.button,
120
+ typeStyles(type, disabled, colors),
121
+ rounded && { borderRadius },
122
+ isFullWidth && { width: '100%' },
123
+ (disabled || loading) && styles.disabled,
124
+ ]);
125
+ }, [type, disabled, loading, rounded, borderRadius, isFullWidth, colors]);
126
+
127
+ const textColor = useMemo(() => {
128
+ return type === "cancel" ? { color: colors.text.hex } : { color: colors.textButton.hex };
129
+ }, [type, colors]);
130
+
131
+ // Safely try to access handleSubmit from the form context
132
+ const formContext = (() => {
133
+ try {
134
+ return useFormContext();
135
+ } catch {
136
+ return null;
137
+ }
138
+ })();
139
+
140
+ const handlePress = () => {
141
+ if (type === 'submit' && formContext?.handleSubmit) {
142
+ console.log("Its submit type");
143
+
144
+ formContext.handleSubmit();
145
+ } else if (onPress) {
146
+ onPress();
147
+ }
148
+ };
149
+
150
+
151
+ return (
152
+ <TouchableOpacity
153
+ style={computedStyles as ViewStyle}
154
+ disabled={disabled || loading}
155
+ onPress={handlePress}
156
+ activeOpacity={0.7}
157
+ >
158
+ {loading ? ( // Show loading spinner if loading
159
+ <ActivityIndicator size="small" color={colors.textButton.hex} />
160
+ ) : (
161
+ <Text style={textColor}>
162
+ {Array.isArray(children) ? children.join('').toUpperCase() : children?.toUpperCase()}
163
+ </Text>
164
+ )}
165
+ </TouchableOpacity>
166
+ );
167
+ };
168
+
169
+ const styles = StyleSheet.create({
170
+ button: {
171
+ justifyContent: 'center',
172
+ alignItems: 'center',
173
+ paddingVertical: 10,
174
+ paddingHorizontal: 20,
175
+ },
176
+ disabled: {
177
+ opacity: 0.6,
178
+ },
179
+ });
180
+
@@ -0,0 +1,137 @@
1
+ // src/fonts/Text.tsx
2
+
3
+ import { ThemeColors, ThemeContext, ThemeFonts } from 'aport-themes';
4
+ import React, { useContext } from 'react';
5
+ import { Text as RNText, StyleSheet, TextProps, TextStyle } from 'react-native';
6
+
7
+ interface CustomTextProps extends TextProps {
8
+ /**
9
+ * Content to be displayed inside the Text component.
10
+ */
11
+ children: React.ReactNode;
12
+
13
+ /**
14
+ * Size of the text. Defaults to 14.
15
+ */
16
+ size?: number;
17
+
18
+ /**
19
+ * If true, applies bold styling to the text.
20
+ */
21
+ b?: boolean;
22
+
23
+ /**
24
+ * If true, applies italic styling to the text.
25
+ */
26
+ i?: boolean;
27
+
28
+ /**
29
+ * If true, applies underline styling to the text.
30
+ */
31
+ u?: boolean;
32
+
33
+ /**
34
+ * Paragraph alignment. Can be 'left', 'center', or 'right'. Defaults to 'left'.
35
+ */
36
+ align?: 'left' | 'center' | 'right' | 'justify'; // Paragraph alignment
37
+
38
+ /**
39
+ * Text type. Defaults to 'text'. Should match the keys in ThemeColors.
40
+ * This restricts type to known color keys like 'primary', 'error', etc.
41
+ */
42
+ type?: keyof ThemeColors;
43
+
44
+ /**
45
+ * Text font type. Defaults to 'body'. Should match the keys in ThemeFonts.
46
+ * This restricts type to known fonts keys like 'primary', 'secundary', etc.
47
+ */
48
+ typeFont?: keyof ThemeFonts; // <-- New prop to select font type
49
+
50
+ /**
51
+ * Header level. Accepts 0 (none), 1, 2, or 3. Defaults to 0.
52
+ */
53
+ h?: 0 | 1 | 2 | 3;
54
+
55
+ /**
56
+ * Additional styles to apply to the Text component.
57
+ */
58
+ style?: TextStyle | TextStyle[];
59
+ }
60
+
61
+ /**
62
+ * A dynamic Text component that supports HTML-like formatting.
63
+ * Integrates with the Theme system for consistent styling.
64
+ *
65
+ * @param children - The content to be displayed inside the Text component.
66
+ * @param size - Size of the text. Defaults to 'medium'.
67
+ * @param b - If true, applies bold styling.
68
+ * @param i - If true, applies italic styling.
69
+ * @param type - Type of Text component. Defaults to 'text'.
70
+ * @param typeFont - Type of Font component. Defaults to 'body'.
71
+ * @param u - If true, applies underline styling.
72
+ * @param align - Paragraph alignment. Defaults to 'left'.
73
+ * @param h - Header level. Accepts 0 (none), 1, 2, or 3. Defaults to 0.
74
+ * @param style - Additional styles to apply.
75
+ */
76
+ export const Text: React.FC<CustomTextProps> = ({
77
+ children,
78
+ size = 14,
79
+ b = false,
80
+ i = false,
81
+ u = false,
82
+ align = 'left',
83
+ type = 'text',
84
+ typeFont = 'body',
85
+ h = 0,
86
+ style,
87
+ }) => {
88
+ const { theme } = useContext(ThemeContext);
89
+ const { colors, fonts } = theme;
90
+
91
+ // Determine font family and size based on 'typeFont'
92
+ const fontSettings = fonts[typeFont] || fonts.body;
93
+ const fontFamily = fontSettings.fontFamily;
94
+ let fontSize = fontSettings.fontSize || size;
95
+
96
+ // Calculate header size based on 'h' prop
97
+ if (h === 1) fontSize = 32;
98
+ else if (h === 2) fontSize = 24;
99
+ else if (h === 3) fontSize = 18;
100
+
101
+ // Define font weight based on bold prop
102
+ const fontWeight = b ? '700' : fontSettings.fontWeight || '400';
103
+
104
+ // Define font style based on italic prop
105
+ const fontStyle = i ? 'italic' : 'normal';
106
+
107
+ // Define text decoration based on underline prop
108
+ const textDecorationLine = u ? 'underline' : 'none';
109
+
110
+ // Define text alignment
111
+ const textAlign: TextStyle['textAlign'] = align;
112
+ // Map the 'type' prop to the correct color from the theme
113
+ const textColor = colors[type]?.hex || colors.text.hex;
114
+
115
+ // Combine all styles
116
+ const textStyles: TextStyle = {
117
+ fontSize,
118
+ fontWeight,
119
+ fontFamily,
120
+ fontStyle,
121
+ textDecorationLine,
122
+ textAlign,
123
+ color: textColor,
124
+ };
125
+
126
+
127
+ return (
128
+ <RNText style={[textStyles, style]}>
129
+ {children}
130
+ </RNText>
131
+ );
132
+ };
133
+
134
+ const styles = StyleSheet.create({
135
+ // Define any default styles if needed
136
+ });
137
+
@@ -1 +1,2 @@
1
1
  export { Text } from "./Text";
2
+
@@ -0,0 +1,47 @@
1
+ // src/forms/ErrorList.tsx
2
+
3
+ import React, { useContext } from 'react';
4
+ import { View, StyleSheet } from 'react-native';
5
+ import { Text } from '../fonts/Text';
6
+ import { ThemeContext } from 'aport-themes';
7
+
8
+ interface ErrorListProps {
9
+ errors: string[];
10
+ }
11
+
12
+ const ErrorList: React.FC<ErrorListProps> = ({ errors }) => {
13
+ const { theme } = useContext(ThemeContext);
14
+ const { colors } = theme;
15
+
16
+ return (
17
+ <View style={styles.container}>
18
+ {errors.map((error, index) => (
19
+ <View key={index} style={styles.errorItem}>
20
+ <Text style={[styles.bullet, { color: colors.error.hex }]}>•</Text>
21
+ <Text style={[styles.errorText, { color: colors.error.hex }]}>{error}</Text>
22
+ </View>
23
+ ))}
24
+ </View>
25
+ );
26
+ };
27
+
28
+ const styles = StyleSheet.create({
29
+ container: {
30
+ marginTop: 4,
31
+ },
32
+ errorItem: {
33
+ flexDirection: 'row',
34
+ alignItems: 'flex-start',
35
+ marginBottom: 2,
36
+ },
37
+ bullet: {
38
+ marginRight: 4,
39
+ fontSize: 12,
40
+ },
41
+ errorText: {
42
+ flex: 1,
43
+ fontSize: 12,
44
+ },
45
+ });
46
+
47
+ export default ErrorList;
@@ -0,0 +1,87 @@
1
+ Input Component Documentation
2
+ File Path
3
+ src/forms/Input.tsx
4
+
5
+ Description
6
+ The Input component is a versatile and reusable form input field designed to handle various input types with built-in validation and error display functionalities. It integrates seamlessly with the theme system to adapt its styles based on the current theme (light or dark). The component supports automatic formatting for specific input types such as phone numbers and identification fields, enhancing user experience and ensuring data consistency.
7
+
8
+ Component Overview
9
+ Labels: Displays a label above the input field.
10
+ Error Handling: Shows a list of error messages below the input field when validation fails.
11
+ Input Types: Supports different input formats (phone, id, uppercase, numeric) with automatic formatting.
12
+ Theming: Adapts styles based on the active theme, utilizing the body color for backgrounds in dark mode.
13
+ Controlled Component: Manages its state through the FormContext, allowing centralized form management.
14
+ Props
15
+ Prop Type Required Description
16
+ name string Yes The unique identifier for the input field, used to manage its state within the form.
17
+ label string Yes The text label displayed above the input field.
18
+ inputType 'phone' | 'id' | 'uppercase' | 'numeric' No Specifies the type of input and applies corresponding formatting. Defaults to standard text input.
19
+ style TextInputProps['style'] No Additional styles to customize the appearance of the TextInput component.
20
+ ...rest TextInputProps No Spread any additional TextInput props to allow further customization and flexibility.
21
+
22
+ Supported inputType Values
23
+ phone: Formats the input as a phone number (xxx-xxx-xxxx), automatically inserting hyphens.
24
+ id: Converts all input characters to uppercase, suitable for identification numbers like IDs, passports, and visas.
25
+ uppercase: Forces all input characters to uppercase, useful for fields like license plates or certain codes.
26
+ numeric: Restricts input to numeric characters only, ideal for fields like ZIP codes, ages, or any numerical data.
27
+ Usage Example
28
+ tsx
29
+ Copy code
30
+ // ExampleUsage.tsx
31
+
32
+ import React from 'react';
33
+ import { ScrollView, View } from 'react-native';
34
+ import { Form } from './forms/FormContext';
35
+ import { Input } from './forms/Input';
36
+ import { Button } from '../components/Button';
37
+
38
+ const MyFormScreen: React.FC = () => {
39
+ const handleFormSubmit = async (formValues: Record<string, any>) => {
40
+ const errors: Record<string, string[]> = {};
41
+
42
+ // Validate the 'name' field
43
+ if (!formValues.name) {
44
+ errors.name = ['Name is required'];
45
+ }
46
+
47
+ // Validate the 'email' field
48
+ if (!formValues.email) {
49
+ errors.email = ['Email is required'];
50
+ } else {
51
+ if (formValues.email.length < 4) {
52
+ errors.email = [...(errors.email || []), 'Email is too short'];
53
+ }
54
+ if (!formValues.email.includes('@')) {
55
+ errors.email = [...(errors.email || []), 'Email must include @'];
56
+ }
57
+ }
58
+
59
+ // Validate the 'phone' field
60
+ if (!formValues.phone) {
61
+ errors.phone = ['Phone is required'];
62
+ }
63
+
64
+ // Return validation errors if any exist
65
+ return errors;
66
+
67
+ };
68
+
69
+ return (
70
+ <ScrollView>
71
+ <Form onSubmit={handleFormSubmit}>
72
+ <View style={{ padding: 16 }}>
73
+ <Input name="name" label="First Name" inputType="uppercase" />
74
+ <Input name="lastName" label="Last Name" inputType="uppercase" />
75
+ <Input name="email" label="Email" keyboardType="email-address" inputType="id" />
76
+ <Input name="phone" label="Phone" keyboardType="number-pad" maxLength={12} inputType="phone" />
77
+
78
+ {/* Form submit button */}
79
+ <Button type="submit">Submit</Button>
80
+ </View>
81
+ </Form>
82
+ </ScrollView>
83
+
84
+ );
85
+ };
86
+
87
+ export default MyFormScreen;
@@ -1 +1,3 @@
1
+ // src/forms/Form.tsx
2
+
1
3
  export { Form, useFormContext, setFormValueGlobal } from './FormContext';