@umituz/react-native-auth 3.4.14 → 3.4.18
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 +5 -9
- package/src/infrastructure/services/initializeAuth.ts +7 -1
- package/src/presentation/components/AuthBottomSheet.styles.ts +1 -1
- package/src/presentation/components/AuthBottomSheet.tsx +10 -6
- package/src/presentation/components/LoginForm.tsx +10 -2
- package/src/presentation/components/RegisterForm.tsx +22 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.18",
|
|
4
4
|
"description": "Authentication service for React Native apps - Secure, type-safe, and production-ready. Provider-agnostic design with dependency injection, configurable validation, and comprehensive error handling.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@umituz/react-native-localization": "latest",
|
|
37
37
|
"@umituz/react-native-storage": "latest",
|
|
38
38
|
"@umituz/react-native-tanstack": "latest",
|
|
39
|
-
"@umituz/react-native-validation": "
|
|
39
|
+
"@umituz/react-native-validation": "^1.4.7"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@gorhom/bottom-sheet": ">=4.0.0",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@expo/vector-icons": "^15.0.3",
|
|
60
60
|
"@gorhom/bottom-sheet": "^5.0.0",
|
|
61
|
-
"@react-native-async-storage/async-storage": "^
|
|
61
|
+
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
62
62
|
"@react-native-community/datetimepicker": "^8.5.1",
|
|
63
63
|
"@react-navigation/bottom-tabs": "^7.9.0",
|
|
64
64
|
"@react-navigation/native": "^7.1.26",
|
|
@@ -68,15 +68,11 @@
|
|
|
68
68
|
"@types/react": "~19.1.0",
|
|
69
69
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
70
70
|
"@typescript-eslint/parser": "^7.0.0",
|
|
71
|
-
"@umituz/react-native-design-system": "
|
|
71
|
+
"@umituz/react-native-design-system": "latest",
|
|
72
72
|
"@umituz/react-native-design-system-theme": "latest",
|
|
73
|
-
"@umituz/react-native-
|
|
73
|
+
"@umituz/react-native-filesystem": "latest",
|
|
74
74
|
"@umituz/react-native-haptics": "latest",
|
|
75
|
-
"@umituz/react-native-localization": "latest",
|
|
76
|
-
"@umituz/react-native-storage": "latest",
|
|
77
|
-
"@umituz/react-native-tanstack": "latest",
|
|
78
75
|
"@umituz/react-native-uuid": "latest",
|
|
79
|
-
"@umituz/react-native-validation": "latest",
|
|
80
76
|
"eslint": "^8.57.0",
|
|
81
77
|
"expo-apple-authentication": "^6.0.0",
|
|
82
78
|
"expo-application": "^7.0.8",
|
|
@@ -18,6 +18,8 @@ import { collectDeviceExtras } from "@umituz/react-native-design-system";
|
|
|
18
18
|
import { initializeAuthListener } from "../../presentation/stores/initializeAuthListener";
|
|
19
19
|
import type { AuthConfig } from "../../domain/value-objects/AuthConfig";
|
|
20
20
|
|
|
21
|
+
import type { IStorageProvider } from "./AuthPackage";
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* Unified auth initialization options
|
|
23
25
|
*/
|
|
@@ -31,6 +33,9 @@ export interface InitializeAuthOptions {
|
|
|
31
33
|
/** Callback to collect device/app info for user documents */
|
|
32
34
|
collectExtras?: () => Promise<Record<string, unknown>>;
|
|
33
35
|
|
|
36
|
+
/** Storage provider for persisting auth state (e.g. anonymous mode) */
|
|
37
|
+
storageProvider?: IStorageProvider;
|
|
38
|
+
|
|
34
39
|
/** Enable auto anonymous sign-in (default: true) */
|
|
35
40
|
autoAnonymousSignIn?: boolean;
|
|
36
41
|
|
|
@@ -91,6 +96,7 @@ export async function initializeAuth(
|
|
|
91
96
|
userCollection = "users",
|
|
92
97
|
extraFields,
|
|
93
98
|
collectExtras,
|
|
99
|
+
storageProvider,
|
|
94
100
|
autoAnonymousSignIn = true,
|
|
95
101
|
onUserConverted,
|
|
96
102
|
onAuthStateChange,
|
|
@@ -115,7 +121,7 @@ export async function initializeAuth(
|
|
|
115
121
|
|
|
116
122
|
// 3. Initialize AuthService (for email/password auth)
|
|
117
123
|
try {
|
|
118
|
-
await initializeAuthService(auth, authConfig);
|
|
124
|
+
await initializeAuthService(auth, authConfig, storageProvider);
|
|
119
125
|
} catch {
|
|
120
126
|
// AuthService initialization failed, but we can continue
|
|
121
127
|
// Email/password auth won't work, but social/anonymous will
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
BottomSheetScrollView,
|
|
12
12
|
} from "@gorhom/bottom-sheet";
|
|
13
13
|
import type { BottomSheetBackdropProps } from "@gorhom/bottom-sheet";
|
|
14
|
-
import { useAppDesignTokens, AtomicText, AtomicIcon } from "@umituz/react-native-design-system";
|
|
14
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon, AtomicKeyboardAvoidingView } from "@umituz/react-native-design-system";
|
|
15
15
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
16
16
|
import { useAuthModalStore } from "../stores/authModalStore";
|
|
17
17
|
import { useAuth } from "../hooks/useAuth";
|
|
@@ -124,16 +124,19 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
124
124
|
backdropComponent={renderBackdrop}
|
|
125
125
|
onDismiss={handleDismiss}
|
|
126
126
|
enablePanDownToClose
|
|
127
|
-
keyboardBehavior="
|
|
127
|
+
keyboardBehavior="extend"
|
|
128
128
|
keyboardBlurBehavior="restore"
|
|
129
129
|
backgroundStyle={[styles.background, { backgroundColor: tokens.colors.backgroundPrimary }]}
|
|
130
130
|
handleIndicatorStyle={[styles.handleIndicator, { backgroundColor: tokens.colors.border }]}
|
|
131
131
|
>
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
showsVerticalScrollIndicator={false}
|
|
135
|
-
keyboardShouldPersistTaps="handled"
|
|
132
|
+
<AtomicKeyboardAvoidingView
|
|
133
|
+
style={{ flex: 1 }}
|
|
136
134
|
>
|
|
135
|
+
<BottomSheetScrollView
|
|
136
|
+
contentContainerStyle={styles.scrollContent}
|
|
137
|
+
showsVerticalScrollIndicator={false}
|
|
138
|
+
keyboardShouldPersistTaps="handled"
|
|
139
|
+
>
|
|
137
140
|
<TouchableOpacity
|
|
138
141
|
style={styles.closeButton}
|
|
139
142
|
onPress={handleClose}
|
|
@@ -177,6 +180,7 @@ export const AuthBottomSheet: React.FC<AuthBottomSheetProps> = ({
|
|
|
177
180
|
)}
|
|
178
181
|
</View>
|
|
179
182
|
</BottomSheetScrollView>
|
|
183
|
+
</AtomicKeyboardAvoidingView>
|
|
180
184
|
</BottomSheetModal>
|
|
181
185
|
);
|
|
182
186
|
};
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Single Responsibility: Render login form UI
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React from "react";
|
|
7
|
-
import { View, StyleSheet } from "react-native";
|
|
6
|
+
import React, { useRef } from "react";
|
|
7
|
+
import { View, StyleSheet, TextInput } from "react-native";
|
|
8
8
|
import { AtomicInput, AtomicButton } from "@umituz/react-native-design-system";
|
|
9
9
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
10
10
|
import { useLoginForm } from "../hooks/useLoginForm";
|
|
@@ -17,6 +17,7 @@ interface LoginFormProps {
|
|
|
17
17
|
|
|
18
18
|
export const LoginForm: React.FC<LoginFormProps> = ({ onNavigateToRegister }) => {
|
|
19
19
|
const { t } = useLocalization();
|
|
20
|
+
const passwordRef = useRef<TextInput>(null);
|
|
20
21
|
const {
|
|
21
22
|
email,
|
|
22
23
|
password,
|
|
@@ -42,20 +43,27 @@ export const LoginForm: React.FC<LoginFormProps> = ({ onNavigateToRegister }) =>
|
|
|
42
43
|
disabled={loading}
|
|
43
44
|
state={emailError ? "error" : "default"}
|
|
44
45
|
helperText={emailError || undefined}
|
|
46
|
+
returnKeyType="next"
|
|
47
|
+
onSubmitEditing={() => passwordRef.current?.focus()}
|
|
48
|
+
blurOnSubmit={false}
|
|
45
49
|
/>
|
|
46
50
|
</View>
|
|
47
51
|
|
|
48
52
|
<View style={styles.inputContainer}>
|
|
49
53
|
<AtomicInput
|
|
54
|
+
ref={passwordRef}
|
|
50
55
|
label={t("auth.password")}
|
|
51
56
|
value={password}
|
|
52
57
|
onChangeText={handlePasswordChange}
|
|
53
58
|
placeholder={t("auth.passwordPlaceholder")}
|
|
54
59
|
secureTextEntry
|
|
60
|
+
showPasswordToggle
|
|
55
61
|
autoCapitalize="none"
|
|
56
62
|
disabled={loading}
|
|
57
63
|
state={passwordError ? "error" : "default"}
|
|
58
64
|
helperText={passwordError || undefined}
|
|
65
|
+
returnKeyType="done"
|
|
66
|
+
onSubmitEditing={() => { void handleSignIn(); }}
|
|
59
67
|
/>
|
|
60
68
|
</View>
|
|
61
69
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Single Responsibility: Render register form UI
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React from "react";
|
|
7
|
-
import { View, StyleSheet } from "react-native";
|
|
6
|
+
import React, { useRef } from "react";
|
|
7
|
+
import { View, StyleSheet, TextInput } from "react-native";
|
|
8
8
|
import { AtomicInput, AtomicButton } from "@umituz/react-native-design-system";
|
|
9
9
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
10
10
|
import { useRegisterForm } from "../hooks/useRegisterForm";
|
|
@@ -30,6 +30,10 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
|
|
|
30
30
|
onPrivacyPress,
|
|
31
31
|
}) => {
|
|
32
32
|
const { t } = useLocalization();
|
|
33
|
+
const emailRef = useRef<TextInput>(null);
|
|
34
|
+
const passwordRef = useRef<TextInput>(null);
|
|
35
|
+
const confirmPasswordRef = useRef<TextInput>(null);
|
|
36
|
+
|
|
33
37
|
const {
|
|
34
38
|
displayName,
|
|
35
39
|
email,
|
|
@@ -61,11 +65,15 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
|
|
|
61
65
|
disabled={loading}
|
|
62
66
|
state={fieldErrors.displayName ? "error" : "default"}
|
|
63
67
|
helperText={fieldErrors.displayName || undefined}
|
|
68
|
+
returnKeyType="next"
|
|
69
|
+
onSubmitEditing={() => emailRef.current?.focus()}
|
|
70
|
+
blurOnSubmit={false}
|
|
64
71
|
/>
|
|
65
72
|
</View>
|
|
66
73
|
|
|
67
74
|
<View style={styles.inputContainer}>
|
|
68
75
|
<AtomicInput
|
|
76
|
+
ref={emailRef}
|
|
69
77
|
label={t("auth.email")}
|
|
70
78
|
value={email}
|
|
71
79
|
onChangeText={handleEmailChange}
|
|
@@ -75,20 +83,28 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
|
|
|
75
83
|
disabled={loading}
|
|
76
84
|
state={fieldErrors.email ? "error" : "default"}
|
|
77
85
|
helperText={fieldErrors.email || undefined}
|
|
86
|
+
returnKeyType="next"
|
|
87
|
+
onSubmitEditing={() => passwordRef.current?.focus()}
|
|
88
|
+
blurOnSubmit={false}
|
|
78
89
|
/>
|
|
79
90
|
</View>
|
|
80
91
|
|
|
81
92
|
<View style={styles.inputContainer}>
|
|
82
93
|
<AtomicInput
|
|
94
|
+
ref={passwordRef}
|
|
83
95
|
label={t("auth.password")}
|
|
84
96
|
value={password}
|
|
85
97
|
onChangeText={handlePasswordChange}
|
|
86
98
|
placeholder={t("auth.passwordPlaceholder")}
|
|
87
99
|
secureTextEntry
|
|
100
|
+
showPasswordToggle
|
|
88
101
|
autoCapitalize="none"
|
|
89
102
|
disabled={loading}
|
|
90
103
|
state={fieldErrors.password ? "error" : "default"}
|
|
91
104
|
helperText={fieldErrors.password || undefined}
|
|
105
|
+
returnKeyType="next"
|
|
106
|
+
onSubmitEditing={() => confirmPasswordRef.current?.focus()}
|
|
107
|
+
blurOnSubmit={false}
|
|
92
108
|
/>
|
|
93
109
|
{password.length > 0 && (
|
|
94
110
|
<PasswordStrengthIndicator requirements={passwordRequirements} />
|
|
@@ -97,6 +113,7 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
|
|
|
97
113
|
|
|
98
114
|
<View style={styles.inputContainer}>
|
|
99
115
|
<AtomicInput
|
|
116
|
+
ref={confirmPasswordRef}
|
|
100
117
|
label={t("auth.confirmPassword")}
|
|
101
118
|
value={confirmPassword}
|
|
102
119
|
onChangeText={handleConfirmPasswordChange}
|
|
@@ -104,10 +121,13 @@ export const RegisterForm: React.FC<RegisterFormProps> = ({
|
|
|
104
121
|
t("auth.confirmPasswordPlaceholder")
|
|
105
122
|
}
|
|
106
123
|
secureTextEntry
|
|
124
|
+
showPasswordToggle
|
|
107
125
|
autoCapitalize="none"
|
|
108
126
|
disabled={loading}
|
|
109
127
|
state={fieldErrors.confirmPassword ? "error" : "default"}
|
|
110
128
|
helperText={fieldErrors.confirmPassword || undefined}
|
|
129
|
+
returnKeyType="done"
|
|
130
|
+
onSubmitEditing={() => { void handleSignUp(); }}
|
|
111
131
|
/>
|
|
112
132
|
{confirmPassword.length > 0 && (
|
|
113
133
|
<PasswordMatchIndicator isMatch={passwordsMatch} />
|