@towsila/expo-ui-library 3.2.4 → 3.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towsila/expo-ui-library",
3
- "version": "3.2.4",
3
+ "version": "3.3.0",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,17 +1,16 @@
1
- import ErrorMessage from "../ui/error";
2
- import { textSize, Fonts } from "../../tokens/typography";
3
- import { useAppTheme } from "../../context/ThemeContext";
4
- import { useLoginForm } from "../../hooks/useLoginForm";
1
+
5
2
  import {
6
- StyleSheet,
7
3
  Text, TouchableOpacity, View,
8
4
  } from "react-native";
9
- import TemplatePage from "../reusable/templatePage";
5
+
6
+ import Input from "../ui/input";
7
+ import { useAppTheme } from "../../context/ThemeContext";
8
+ import { useLoginForm } from "../../hooks/useLoginForm";
9
+ import { useLanguage } from "../../context/LanguageContext";
10
+ import ScreenHeader from "../ui/PageTopBar";
10
11
  import SharpButton from "../ui/sharpButton";
11
- import SharpInput from "../ui/sharpInput";
12
- import Google from "../../assets/icons/google.svg"
12
+ import { Fonts, textSize } from "../../tokens/typography";
13
13
  import SharpContainer from "../ui/sharpContainer";
14
- import {Email, Eye,EyeOff, LockClosed } from "@towsila/icons";
15
14
  interface LoginScreenProps {
16
15
  title?: string;
17
16
  subtitle?: string;
@@ -53,20 +52,17 @@ export default function LoginScreen({
53
52
  googleLabel,
54
53
  t,
55
54
  }: LoginScreenProps) {
56
- const { colors, isDark } = useAppTheme();
55
+ const { colors } = useAppTheme();
57
56
  const form = useLoginForm({ onLogin });
58
-
57
+ const {isRTL} = useLanguage();
59
58
  return (
60
- <TemplatePage title={title}
61
- subtitle={subtitle}
62
- body={
63
- <>
64
- {errorMessage && <ErrorMessage message={errorMessage} position="center" fontSize={textSize.md} />}
65
- <View style={{ marginBottom: 15 }}>
66
- <SharpInput
59
+ <View style={{ flex: 1, paddingHorizontal: 20, paddingTop: 60 ,}}>
60
+ <ScreenHeader title={title} description={subtitle} />
61
+ <View style={{ marginBottom: 20, marginTop: 50, padding: 15, borderRadius: 10, gap: 20 }}>
62
+ <Input
67
63
  label={emailLabel}
68
64
  value={form.values.email}
69
- onChangeText={(text)=>form.setValue("email", text)}
65
+ onChangeText={(text) => form.setValue("email", text)}
70
66
  placeholder={emailPlaceholder}
71
67
  keyboardType="email-address"
72
68
  error={form.errors.email ? t?.(form.errors.email) : ""}
@@ -75,88 +71,74 @@ export default function LoginScreen({
75
71
  textContentType="emailAddress"
76
72
  returnKeyType="next"
77
73
  onClearError={() => form.clearError("email")}
78
- iconLeft={(color)=><Email width={18} height={18} color={color}/>}
79
- />
80
- </View>
81
-
82
- <View style={{ marginBottom: 20 }}>
83
- <SharpInput
74
+ iconLeft={"mail-outline"}
75
+ />
76
+ <Input
84
77
  label={passwordLabel}
85
78
  value={form.values.password}
86
79
  onChangeText={(value) => form.setValue("password", value)}
87
80
  placeholder={passwordPlaceholder}
88
- iconRight={form.showPassword ? (color)=><EyeOff width={18} height={18} color={color}/> : (color)=><Eye width={18} height={18} color={color}/>}
81
+ iconRight={form.showPassword ? "eye-off-outline" : "eye-outline"}
89
82
  onPressIconRight={() => form.setShowPassword(!form.showPassword)}
90
83
  secureTextEntry={!form.showPassword}
91
84
  textContentType="password"
92
85
  returnKeyType="done"
93
86
  error={form.errors.password ? t?.(form.errors.password) : ""}
94
87
  onClearError={() => form.clearError("password")}
95
- iconLeft={(color)=><LockClosed width={18} height={18} color={color}/>}
96
- />
88
+ iconLeft={"lock-closed-outline"}
89
+ />
90
+ <View style={{gap:10}}>
91
+ <SharpButton text={loginButtonLabel} bgColor={colors.primary} onPress={form.handleSubmit} height={50} loading={form.loading} />
92
+ <TouchableOpacity onPress={onForgotPassword} activeOpacity={0.7} style={{ alignSelf: isRTL ?"flex-start" :"flex-end" }}>
93
+ <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
94
+ {forgotPasswordLabel}
95
+ </Text>
96
+ </TouchableOpacity>
97
97
  </View>
98
-
99
- <SharpButton text={loginButtonLabel} bgColor={colors.primary} onPress={form.handleSubmit} height={50} loading={form.loading}/>
100
-
101
- <TouchableOpacity onPress={onForgotPassword} activeOpacity={0.7} style={{ alignSelf: "flex-end", marginTop: 14 }}>
102
- <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
103
- {forgotPasswordLabel}
104
- </Text>
105
- </TouchableOpacity>
106
- </>
107
- }
108
- footer={
109
- <View style={{flex: 1, justifyContent: "space-between"}}>
98
+ </View>
99
+
100
+ <View style={{ flex: 1, justifyContent: "space-between" }}>
110
101
  {(onGoogleLogin) && (
111
- <View>
112
- <View style={{ flexDirection: "row", alignItems: "center", gap: 12, marginVertical: 20, marginHorizontal: 20 }}>
113
- <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
114
- <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
115
- {dividerLabel}
116
- </Text>
117
- <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
102
+ <View>
103
+ <View style={{ flexDirection: isRTL? "row-reverse": "row", alignItems: "center", gap: 12, marginVertical: 20, marginHorizontal: 20 }}>
104
+ <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
105
+ <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
106
+ {dividerLabel}
107
+ </Text>
108
+ <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
109
+ </View>
110
+ <View style={{ marginHorizontal: 28 }}>
111
+ <SharpContainer
112
+ bgColor={colors.background.main}
113
+ borderColor={colors.text.primary}
114
+ height={50}
115
+ >
116
+ <TouchableOpacity style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 10 }} onPress={onGoogleLogin}>
117
+ {/* <Google width={20} height={20} /> */}
118
+ <Text style={{
119
+ fontSize: textSize.sm,
120
+ fontFamily: Fonts.montserrat.semiBold,
121
+ color: colors.text.primary,
122
+ }}>
123
+ {googleLabel}
124
+ </Text>
125
+ </TouchableOpacity>
126
+ </SharpContainer>
127
+ </View>
118
128
  </View>
119
- <View style={{marginHorizontal: 28}}>
120
- <SharpContainer
121
- bgColor={colors.background.main}
122
- borderColor={colors.text.primary}
123
- height={50}
124
- >
125
- <TouchableOpacity style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 10 }} onPress={onGoogleLogin}>
126
- <Google width={20} height={20} />
127
- <Text style={{
128
- fontSize: textSize.sm,
129
- fontFamily: Fonts.montserrat.semiBold,
130
- color: colors.text.primary,
131
- }}>
132
- {googleLabel}
133
- </Text>
134
- </TouchableOpacity>
135
- </SharpContainer>
136
- </View>
137
- </View>
138
129
  )}
139
130
 
140
- <View style={{ flexDirection: "row", justifyContent: "center", gap: 4, marginBottom: 40 }}>
141
- <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
142
- {noAccountLabel}
143
- </Text>
144
- <TouchableOpacity onPress={onSignUp} activeOpacity={0.7}>
145
- <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
146
- {signUpLabel}
131
+ <View style={{ flexDirection: "row", justifyContent: "center", gap: 4, marginBottom: 70 }}>
132
+ <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
133
+ {noAccountLabel}
147
134
  </Text>
148
- </TouchableOpacity>
135
+ <TouchableOpacity onPress={onSignUp} activeOpacity={0.7}>
136
+ <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
137
+ {signUpLabel}
138
+ </Text>
139
+ </TouchableOpacity>
149
140
  </View>
150
- </View>
151
- }
152
- />
141
+ </View>
142
+ </View>
153
143
  );
154
- }
155
-
156
-
157
- const styles = StyleSheet.create({
158
- socialIcons:{
159
- alignItems: "center",
160
- justifyContent: "center"
161
- }
162
- })
144
+ }
@@ -45,7 +45,7 @@ export default function OnBoarding({
45
45
  >
46
46
  {/* ---------- Header ---------- */}
47
47
  <View style={{minHeight: 40,}}>
48
- <View style={{ height: 44, flexDirection: isRTL? "row-reverse": "row", alignItems: "center", gap: 15}}>
48
+ <View style={{ height: 44, flexDirection: isRTL? "row": "row-reverse", alignItems: "center", gap: 15, justifyContent: "flex-start",}}>
49
49
  <BackIcon onBack={onBack}/>
50
50
  <Text
51
51
  style={{
@@ -8,7 +8,7 @@ import { useLanguage } from "../../context/LanguageContext";
8
8
  interface PageProps{
9
9
  title: string,
10
10
  description: string;
11
- onBack: ()=>void;
11
+ onBack?: ()=>void;
12
12
  }
13
13
 
14
14
  export default function ScreenHeader({title, description, onBack}:PageProps){
@@ -1,15 +1,16 @@
1
1
  import React, { useState, ComponentProps } from "react";
2
2
  import { StyleProp, Text, TextInput, TextInputProps, View, ViewProps } from "react-native";
3
- import { useAppTheme } from "../../context/ThemeContext";
4
- import { textSize, Fonts } from "../../tokens/typography";
5
3
  import { Ionicons } from "@expo/vector-icons";
4
+ import { Fonts, textSize } from "../../tokens/typography";
5
+ import { useAppTheme } from "../../context/ThemeContext";
6
+ import { useLanguage } from "../../context/LanguageContext";
6
7
  import ErrorMessage from "./error";
7
8
  interface InputProps extends TextInputProps {
8
9
  value: string;
9
10
  onChangeText: (text: string) => void;
10
11
  placeholder: string;
11
- iconLeft?: ComponentProps<typeof Ionicons>["name"];
12
- iconRight?: ComponentProps<typeof Ionicons>["name"];
12
+ iconLeft?: ComponentProps<typeof Ionicons>["name"] ;
13
+ iconRight?: ComponentProps<typeof Ionicons>["name"] ;
13
14
  onPressIconRight?: () => void;
14
15
  error?: string;
15
16
  label?:string;
@@ -17,6 +18,8 @@ interface InputProps extends TextInputProps {
17
18
  style?: StyleProp<ViewProps>;
18
19
  labelFontFamily?: string;
19
20
  textFontFamily?: string;
21
+ prefix?: React.ReactNode;
22
+ bgColor?:string;
20
23
  }
21
24
 
22
25
  export default function Input({
@@ -32,10 +35,13 @@ export default function Input({
32
35
  onClearError,
33
36
  labelFontFamily = Fonts.montserrat.semiBold,
34
37
  textFontFamily = Fonts.montserrat.regular,
38
+ prefix,
39
+ bgColor,
35
40
  ...rest
36
41
  }: InputProps) {
37
42
  const { colors } = useAppTheme();
38
43
  const [focused, setFocused] = useState(false);
44
+ const {isRTL} = useLanguage();
39
45
  return (
40
46
  <View style={[style, {marginBottom: 4}]}>
41
47
  {label && (
@@ -43,7 +49,8 @@ export default function Input({
43
49
  color: colors.text.primary,
44
50
  fontSize: textSize.xs,
45
51
  fontFamily: labelFontFamily,
46
- marginBottom: 6,
52
+ marginBottom: 6,
53
+ textAlign: isRTL ? "left" :"right"
47
54
  }}>
48
55
  {label}
49
56
  </Text>
@@ -56,11 +63,11 @@ export default function Input({
56
63
  size={18}
57
64
  color={error ? colors.semantic.error : focused ? colors.primary : colors.text.secondary}
58
65
  style={{
59
- position: "absolute",
60
- left: 14,
61
- top: "50%",
62
- transform: [{ translateY: -9 }],
63
- zIndex: 1,
66
+ position: "absolute",
67
+ [isRTL ? "left" : "right"]: 14,
68
+ top: "50%",
69
+ transform: [{ translateY: -9 }],
70
+ zIndex: 1,
64
71
  }}
65
72
  />
66
73
  )}
@@ -82,18 +89,23 @@ export default function Input({
82
89
  height: 50,
83
90
  borderRadius: 10,
84
91
  fontSize: textSize.sm,
85
- backgroundColor: colors.background.main,
92
+ backgroundColor: bgColor,
86
93
  color: colors.text.primary,
87
94
  fontFamily: textFontFamily,
88
- paddingLeft: iconLeft ? 42 : 16,
89
- paddingRight: iconRight ? 42 : 16,
95
+
96
+ direction: isRTL ? "rtl" : "ltr",
97
+ textAlign: isRTL ? "right" : "left",
98
+
99
+ paddingStart: iconLeft ? 42 : 16,
100
+ paddingEnd: iconRight ? 42 : 16,
101
+
90
102
  borderColor: error
91
- ? colors.semantic.error
92
- : focused
93
- ? colors.primary
94
- : colors.semantic.border,
95
- borderWidth: error ? 1 : focused ? 1.5 : 0.5,
96
- }}
103
+ ? colors.semantic.error
104
+ : focused
105
+ ? colors.primary
106
+ : colors.semantic.border,
107
+ borderWidth: error ? 1.5 : focused ? 1.5 : 1,
108
+ }}
97
109
  {...rest}
98
110
  />
99
111
  {/* icon right */}
@@ -104,17 +116,17 @@ export default function Input({
104
116
  color={colors.text.secondary}
105
117
  onPress={onPressIconRight}
106
118
  style={{
107
- position: "absolute",
108
- right: 14,
109
- top: "50%",
110
- transform: [{ translateY: -9 }],
111
- zIndex: 1,
112
- }}
119
+ position: "absolute",
120
+ [isRTL ? "right" : "left"]: 14,
121
+ top: "50%",
122
+ transform: [{ translateY: -9 }],
123
+ zIndex: 1,
124
+ }}
113
125
  />
114
126
  )}
115
127
  </View>
116
128
  {error && (
117
- <ErrorMessage message={error}/>
129
+ <ErrorMessage message={error} position={isRTL ? "left" : "right"}/>
118
130
  )}
119
131
  </View>
120
132
  );
@@ -105,7 +105,7 @@ export default function Toast({
105
105
  backgroundColor: toastStyle.background,
106
106
  opacity,
107
107
  transform: [{ translateY }],
108
- flexDirection: isRTL ? "row-reverse" : "row",
108
+ flexDirection: isRTL ? "row" : "row-reverse",
109
109
  },
110
110
  ]}
111
111
  >