@towsila/expo-ui-library 3.2.5 → 3.3.1

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.5",
3
+ "version": "3.3.1",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,17 +1,17 @@
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";
14
+ import Google from "../../assets/icons/google.svg";
15
15
  interface LoginScreenProps {
16
16
  title?: string;
17
17
  subtitle?: string;
@@ -53,20 +53,17 @@ export default function LoginScreen({
53
53
  googleLabel,
54
54
  t,
55
55
  }: LoginScreenProps) {
56
- const { colors, isDark } = useAppTheme();
56
+ const { colors } = useAppTheme();
57
57
  const form = useLoginForm({ onLogin });
58
-
58
+ const {isRTL} = useLanguage();
59
59
  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
60
+ <View style={{ flex: 1, paddingHorizontal: 20, paddingTop: 60 ,}}>
61
+ <ScreenHeader title={title} description={subtitle} />
62
+ <View style={{ marginBottom: 20, marginTop: 50, padding: 15, borderRadius: 10, gap: 20 }}>
63
+ <Input
67
64
  label={emailLabel}
68
65
  value={form.values.email}
69
- onChangeText={(text)=>form.setValue("email", text)}
66
+ onChangeText={(text) => form.setValue("email", text)}
70
67
  placeholder={emailPlaceholder}
71
68
  keyboardType="email-address"
72
69
  error={form.errors.email ? t?.(form.errors.email) : ""}
@@ -75,88 +72,74 @@ export default function LoginScreen({
75
72
  textContentType="emailAddress"
76
73
  returnKeyType="next"
77
74
  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
75
+ iconLeft={"mail-outline"}
76
+ />
77
+ <Input
84
78
  label={passwordLabel}
85
79
  value={form.values.password}
86
80
  onChangeText={(value) => form.setValue("password", value)}
87
81
  placeholder={passwordPlaceholder}
88
- iconRight={form.showPassword ? (color)=><EyeOff width={18} height={18} color={color}/> : (color)=><Eye width={18} height={18} color={color}/>}
82
+ iconRight={form.showPassword ? "eye-off-outline" : "eye-outline"}
89
83
  onPressIconRight={() => form.setShowPassword(!form.showPassword)}
90
84
  secureTextEntry={!form.showPassword}
91
85
  textContentType="password"
92
86
  returnKeyType="done"
93
87
  error={form.errors.password ? t?.(form.errors.password) : ""}
94
88
  onClearError={() => form.clearError("password")}
95
- iconLeft={(color)=><LockClosed width={18} height={18} color={color}/>}
96
- />
89
+ iconLeft={"lock-closed-outline"}
90
+ />
91
+ <View style={{gap:10}}>
92
+ <SharpButton text={loginButtonLabel} bgColor={colors.primary} onPress={form.handleSubmit} height={50} loading={form.loading} />
93
+ <TouchableOpacity onPress={onForgotPassword} activeOpacity={0.7} style={{ alignSelf: isRTL ?"flex-start" :"flex-end" }}>
94
+ <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
95
+ {forgotPasswordLabel}
96
+ </Text>
97
+ </TouchableOpacity>
97
98
  </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"}}>
99
+ </View>
100
+
101
+ <View style={{ flex: 1, justifyContent: "space-between" }}>
110
102
  {(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 }} />
103
+ <View>
104
+ <View style={{ flexDirection: isRTL? "row-reverse": "row", alignItems: "center", gap: 12, marginVertical: 20, marginHorizontal: 20 }}>
105
+ <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
106
+ <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
107
+ {dividerLabel}
108
+ </Text>
109
+ <View style={{ flex: 1, height: 1, backgroundColor: colors.text.secondary, opacity: 0.5 }} />
110
+ </View>
111
+ <View style={{ marginHorizontal: 28 }}>
112
+ <SharpContainer
113
+ bgColor={colors.background.main}
114
+ borderColor={colors.text.primary}
115
+ height={50}
116
+ >
117
+ <TouchableOpacity style={{ flexDirection:isRTL ? "row":"row-reverse", alignItems: "center", justifyContent: "center", gap: 10 }} onPress={onGoogleLogin}>
118
+ <Google width={20} height={20} />
119
+ <Text style={{
120
+ fontSize: textSize.sm,
121
+ fontFamily: Fonts.montserrat.semiBold,
122
+ color: colors.text.primary,
123
+ }}>
124
+ {googleLabel}
125
+ </Text>
126
+ </TouchableOpacity>
127
+ </SharpContainer>
128
+ </View>
118
129
  </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
130
  )}
139
131
 
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}
132
+ <View style={{ flexDirection: "row", justifyContent: "center", gap: 4, marginBottom: 70 }}>
133
+ <Text style={{ fontSize: textSize.xs, color: colors.text.secondary, fontFamily: Fonts.montserrat.regular }}>
134
+ {noAccountLabel}
147
135
  </Text>
148
- </TouchableOpacity>
136
+ <TouchableOpacity onPress={onSignUp} activeOpacity={0.7}>
137
+ <Text style={{ fontSize: textSize.xs, color: colors.primary, fontFamily: Fonts.montserrat.semiBold }}>
138
+ {signUpLabel}
139
+ </Text>
140
+ </TouchableOpacity>
149
141
  </View>
150
- </View>
151
- }
152
- />
142
+ </View>
143
+ </View>
153
144
  );
154
- }
155
-
156
-
157
- const styles = StyleSheet.create({
158
- socialIcons:{
159
- alignItems: "center",
160
- justifyContent: "center"
161
- }
162
- })
145
+ }
@@ -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
  >