@sudobility/auth-components-rn 1.0.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/dist/AuthAction.d.ts +7 -0
- package/dist/AuthAction.d.ts.map +1 -0
- package/dist/AuthInline.d.ts +7 -0
- package/dist/AuthInline.d.ts.map +1 -0
- package/dist/AuthProvider.d.ts +15 -0
- package/dist/AuthProvider.d.ts.map +1 -0
- package/dist/AuthScreen.d.ts +7 -0
- package/dist/AuthScreen.d.ts.map +1 -0
- package/dist/Avatar.d.ts +8 -0
- package/dist/Avatar.d.ts.map +1 -0
- package/dist/EmailSignInForm.d.ts +7 -0
- package/dist/EmailSignInForm.d.ts.map +1 -0
- package/dist/EmailSignUpForm.d.ts +7 -0
- package/dist/EmailSignUpForm.d.ts.map +1 -0
- package/dist/ForgotPasswordForm.d.ts +7 -0
- package/dist/ForgotPasswordForm.d.ts.map +1 -0
- package/dist/ProviderButtons.d.ts +7 -0
- package/dist/ProviderButtons.d.ts.map +1 -0
- package/dist/index.cjs.js +1850 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +1850 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/types.d.ts +313 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +64 -0
- package/src/AuthAction.tsx +107 -0
- package/src/AuthInline.tsx +124 -0
- package/src/AuthProvider.tsx +276 -0
- package/src/AuthScreen.tsx +117 -0
- package/src/Avatar.tsx +86 -0
- package/src/EmailSignInForm.tsx +130 -0
- package/src/EmailSignUpForm.tsx +161 -0
- package/src/ForgotPasswordForm.tsx +129 -0
- package/src/ProviderButtons.tsx +106 -0
- package/src/__tests__/AuthAction.test.tsx +261 -0
- package/src/__tests__/AuthProvider.test.tsx +459 -0
- package/src/__tests__/Avatar.test.tsx +165 -0
- package/src/index.ts +52 -0
- package/src/nativewind.d.ts +30 -0
- package/src/types.ts +383 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react-native';
|
|
3
|
+
import { Avatar } from '../Avatar';
|
|
4
|
+
|
|
5
|
+
// Mock @sudobility/components-rn
|
|
6
|
+
jest.mock('@sudobility/components-rn', () => ({
|
|
7
|
+
cn: function () {
|
|
8
|
+
var args = Array.prototype.slice.call(arguments);
|
|
9
|
+
return args.filter(Boolean).join(' ');
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
function createUser(overrides) {
|
|
14
|
+
return Object.assign(
|
|
15
|
+
{
|
|
16
|
+
uid: 'user-1',
|
|
17
|
+
email: 'john@example.com',
|
|
18
|
+
displayName: 'John Doe',
|
|
19
|
+
photoURL: null,
|
|
20
|
+
isAnonymous: false,
|
|
21
|
+
emailVerified: true,
|
|
22
|
+
providerId: 'password',
|
|
23
|
+
},
|
|
24
|
+
overrides
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('Avatar', () => {
|
|
29
|
+
describe('initials display', () => {
|
|
30
|
+
it('shows two-letter initials from full display name', () => {
|
|
31
|
+
var user = createUser({ displayName: 'John Doe', photoURL: null });
|
|
32
|
+
render(<Avatar user={user} />);
|
|
33
|
+
|
|
34
|
+
expect(screen.getByText('JD')).toBeTruthy();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('shows first two chars when display name is single word', () => {
|
|
38
|
+
var user = createUser({ displayName: 'Alice', photoURL: null });
|
|
39
|
+
render(<Avatar user={user} />);
|
|
40
|
+
|
|
41
|
+
expect(screen.getByText('AL')).toBeTruthy();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('uses first and last name initials for multi-word names', () => {
|
|
45
|
+
var user = createUser({
|
|
46
|
+
displayName: 'Mary Jane Watson',
|
|
47
|
+
photoURL: null,
|
|
48
|
+
});
|
|
49
|
+
render(<Avatar user={user} />);
|
|
50
|
+
|
|
51
|
+
expect(screen.getByText('MW')).toBeTruthy();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('falls back to email initials when no display name', () => {
|
|
55
|
+
var user = createUser({
|
|
56
|
+
displayName: null,
|
|
57
|
+
email: 'alice@example.com',
|
|
58
|
+
photoURL: null,
|
|
59
|
+
});
|
|
60
|
+
render(<Avatar user={user} />);
|
|
61
|
+
|
|
62
|
+
expect(screen.getByText('AL')).toBeTruthy();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('shows "?" when no name or email', () => {
|
|
66
|
+
var user = createUser({
|
|
67
|
+
displayName: null,
|
|
68
|
+
email: null,
|
|
69
|
+
photoURL: null,
|
|
70
|
+
});
|
|
71
|
+
render(<Avatar user={user} />);
|
|
72
|
+
|
|
73
|
+
expect(screen.getByText('?')).toBeTruthy();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('photo display', () => {
|
|
78
|
+
it('renders an Image when photoURL is provided', () => {
|
|
79
|
+
var user = createUser({
|
|
80
|
+
photoURL: 'https://example.com/photo.jpg',
|
|
81
|
+
});
|
|
82
|
+
var result = render(<Avatar user={user} />);
|
|
83
|
+
var tree = JSON.stringify(result.toJSON());
|
|
84
|
+
|
|
85
|
+
expect(tree).toContain('https://example.com/photo.jpg');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('size prop', () => {
|
|
90
|
+
it('applies default size of 32', () => {
|
|
91
|
+
var user = createUser({ photoURL: null });
|
|
92
|
+
var result = render(<Avatar user={user} />);
|
|
93
|
+
var tree = JSON.stringify(result.toJSON());
|
|
94
|
+
|
|
95
|
+
expect(tree).toContain('"width":32');
|
|
96
|
+
expect(tree).toContain('"height":32');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('applies custom size', () => {
|
|
100
|
+
var user = createUser({ photoURL: null });
|
|
101
|
+
var result = render(<Avatar user={user} size={64} />);
|
|
102
|
+
var tree = JSON.stringify(result.toJSON());
|
|
103
|
+
|
|
104
|
+
expect(tree).toContain('"width":64');
|
|
105
|
+
expect(tree).toContain('"height":64');
|
|
106
|
+
expect(tree).toContain('"borderRadius":32');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('scales font size based on avatar size', () => {
|
|
110
|
+
var user = createUser({ photoURL: null });
|
|
111
|
+
var result = render(<Avatar user={user} size={100} />);
|
|
112
|
+
var tree = JSON.stringify(result.toJSON());
|
|
113
|
+
|
|
114
|
+
// fontSize should be size * 0.4 = 40
|
|
115
|
+
expect(tree).toContain('"fontSize":40');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('onPress', () => {
|
|
120
|
+
it('renders as Pressable when onPress is provided', () => {
|
|
121
|
+
var onPress = jest.fn();
|
|
122
|
+
var user = createUser({ photoURL: null });
|
|
123
|
+
render(<Avatar user={user} onPress={onPress} />);
|
|
124
|
+
|
|
125
|
+
var button = screen.getByRole('button');
|
|
126
|
+
expect(button).toBeTruthy();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('calls onPress when pressed', () => {
|
|
130
|
+
var onPress = jest.fn();
|
|
131
|
+
var user = createUser({ photoURL: null });
|
|
132
|
+
render(<Avatar user={user} onPress={onPress} />);
|
|
133
|
+
|
|
134
|
+
fireEvent.press(screen.getByRole('button'));
|
|
135
|
+
expect(onPress).toHaveBeenCalledTimes(1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('renders as View (not Pressable) when onPress is not provided', () => {
|
|
139
|
+
var user = createUser({ photoURL: null });
|
|
140
|
+
render(<Avatar user={user} />);
|
|
141
|
+
|
|
142
|
+
expect(screen.queryByRole('button')).toBeNull();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('accessibility', () => {
|
|
147
|
+
it('uses display name for accessibility label on pressable', () => {
|
|
148
|
+
var onPress = jest.fn();
|
|
149
|
+
var user = createUser({ displayName: 'Jane Smith' });
|
|
150
|
+
render(<Avatar user={user} onPress={onPress} />);
|
|
151
|
+
|
|
152
|
+
var button = screen.getByRole('button');
|
|
153
|
+
expect(button.props.accessibilityLabel).toBe('Jane Smith');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('falls back to "User avatar" when no display name', () => {
|
|
157
|
+
var onPress = jest.fn();
|
|
158
|
+
var user = createUser({ displayName: null });
|
|
159
|
+
render(<Avatar user={user} onPress={onPress} />);
|
|
160
|
+
|
|
161
|
+
var button = screen.getByRole('button');
|
|
162
|
+
expect(button.props.accessibilityLabel).toBe('User avatar');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sudobility/auth-components-rn
|
|
3
|
+
* React Native Authentication components with Firebase Auth support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Context and hooks
|
|
7
|
+
export {
|
|
8
|
+
AuthProvider,
|
|
9
|
+
useAuthStatus,
|
|
10
|
+
createDefaultErrorTexts,
|
|
11
|
+
} from './AuthProvider';
|
|
12
|
+
|
|
13
|
+
// Components
|
|
14
|
+
export { AuthScreen } from './AuthScreen';
|
|
15
|
+
export { AuthInline } from './AuthInline';
|
|
16
|
+
export { AuthAction } from './AuthAction';
|
|
17
|
+
export { Avatar } from './Avatar';
|
|
18
|
+
export { ProviderButtons } from './ProviderButtons';
|
|
19
|
+
export { EmailSignInForm } from './EmailSignInForm';
|
|
20
|
+
export { EmailSignUpForm } from './EmailSignUpForm';
|
|
21
|
+
export { ForgotPasswordForm } from './ForgotPasswordForm';
|
|
22
|
+
|
|
23
|
+
// Types
|
|
24
|
+
export type {
|
|
25
|
+
// Provider types
|
|
26
|
+
AuthProviderType,
|
|
27
|
+
AuthProvidersConfig,
|
|
28
|
+
// User types
|
|
29
|
+
AuthUser,
|
|
30
|
+
// Text types (i18n)
|
|
31
|
+
AuthTexts,
|
|
32
|
+
AuthErrorTexts,
|
|
33
|
+
// Callbacks
|
|
34
|
+
AuthCallbacks,
|
|
35
|
+
// Context value
|
|
36
|
+
AuthContextValue,
|
|
37
|
+
// Component props
|
|
38
|
+
AuthProviderProps,
|
|
39
|
+
AuthMode,
|
|
40
|
+
AuthScreenProps,
|
|
41
|
+
AuthInlineProps,
|
|
42
|
+
AuthMenuItem,
|
|
43
|
+
AuthActionProps,
|
|
44
|
+
AvatarProps,
|
|
45
|
+
AuthContentProps,
|
|
46
|
+
EmailSignInFormProps,
|
|
47
|
+
EmailSignUpFormProps,
|
|
48
|
+
ForgotPasswordFormProps,
|
|
49
|
+
ProviderButtonsProps,
|
|
50
|
+
// Tracking
|
|
51
|
+
AuthTrackingData,
|
|
52
|
+
} from './types';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Type declarations for NativeWind className prop
|
|
2
|
+
import 'react-native';
|
|
3
|
+
|
|
4
|
+
declare module 'react-native' {
|
|
5
|
+
interface ViewProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
interface TextProps {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ImageProps {
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
interface PressableProps {
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
interface TouchableOpacityProps {
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ScrollViewProps {
|
|
21
|
+
className?: string;
|
|
22
|
+
contentContainerClassName?: string;
|
|
23
|
+
}
|
|
24
|
+
interface TextInputProps {
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
interface SafeAreaViewProps {
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for auth-components-rn
|
|
3
|
+
* React Native authentication components with Firebase Auth support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ReactNode } from 'react';
|
|
7
|
+
|
|
8
|
+
// ============ Auth Provider Types ============
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Available authentication providers
|
|
12
|
+
*/
|
|
13
|
+
export type AuthProviderType = 'google' | 'apple' | 'email';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for enabled auth providers
|
|
17
|
+
*/
|
|
18
|
+
export interface AuthProvidersConfig {
|
|
19
|
+
/** Which providers to enable */
|
|
20
|
+
providers: AuthProviderType[];
|
|
21
|
+
/** Enable anonymous sign-in fallback */
|
|
22
|
+
enableAnonymous?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ============ User Types ============
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* User information exposed by the auth context
|
|
29
|
+
*/
|
|
30
|
+
export interface AuthUser {
|
|
31
|
+
uid: string;
|
|
32
|
+
email: string | null;
|
|
33
|
+
displayName: string | null;
|
|
34
|
+
photoURL: string | null;
|
|
35
|
+
isAnonymous: boolean;
|
|
36
|
+
emailVerified: boolean;
|
|
37
|
+
providerId: string | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============ Text Types (i18n) ============
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* All text strings for auth components.
|
|
44
|
+
* Consumer provides these for full i18n support.
|
|
45
|
+
*/
|
|
46
|
+
export interface AuthTexts {
|
|
47
|
+
// Titles
|
|
48
|
+
signInTitle: string;
|
|
49
|
+
signInWithEmail: string;
|
|
50
|
+
createAccount: string;
|
|
51
|
+
resetPassword: string;
|
|
52
|
+
|
|
53
|
+
// Buttons
|
|
54
|
+
signIn: string;
|
|
55
|
+
signUp: string;
|
|
56
|
+
logout: string;
|
|
57
|
+
login: string;
|
|
58
|
+
continueWithGoogle: string;
|
|
59
|
+
continueWithApple: string;
|
|
60
|
+
continueWithEmail: string;
|
|
61
|
+
sendResetLink: string;
|
|
62
|
+
backToSignIn: string;
|
|
63
|
+
close: string;
|
|
64
|
+
|
|
65
|
+
// Labels
|
|
66
|
+
email: string;
|
|
67
|
+
password: string;
|
|
68
|
+
confirmPassword: string;
|
|
69
|
+
displayName: string;
|
|
70
|
+
|
|
71
|
+
// Placeholders
|
|
72
|
+
emailPlaceholder: string;
|
|
73
|
+
passwordPlaceholder: string;
|
|
74
|
+
confirmPasswordPlaceholder: string;
|
|
75
|
+
displayNamePlaceholder: string;
|
|
76
|
+
|
|
77
|
+
// Links
|
|
78
|
+
forgotPassword: string;
|
|
79
|
+
noAccount: string;
|
|
80
|
+
haveAccount: string;
|
|
81
|
+
or: string;
|
|
82
|
+
|
|
83
|
+
// Messages
|
|
84
|
+
resetEmailSent: string;
|
|
85
|
+
resetEmailSentDesc: string;
|
|
86
|
+
passwordMismatch: string;
|
|
87
|
+
passwordTooShort: string;
|
|
88
|
+
loading: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Firebase error messages - parameterized for i18n
|
|
93
|
+
*/
|
|
94
|
+
export interface AuthErrorTexts {
|
|
95
|
+
'auth/user-not-found': string;
|
|
96
|
+
'auth/wrong-password': string;
|
|
97
|
+
'auth/invalid-email': string;
|
|
98
|
+
'auth/invalid-credential': string;
|
|
99
|
+
'auth/email-already-in-use': string;
|
|
100
|
+
'auth/weak-password': string;
|
|
101
|
+
'auth/too-many-requests': string;
|
|
102
|
+
'auth/network-request-failed': string;
|
|
103
|
+
'auth/popup-closed-by-user': string;
|
|
104
|
+
'auth/popup-blocked': string;
|
|
105
|
+
'auth/account-exists-with-different-credential': string;
|
|
106
|
+
'auth/operation-not-allowed': string;
|
|
107
|
+
default: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============ Callbacks ============
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Event callbacks for auth operations
|
|
114
|
+
*/
|
|
115
|
+
export interface AuthCallbacks {
|
|
116
|
+
/** Called after successful sign in */
|
|
117
|
+
onSignIn?: (user: AuthUser) => void;
|
|
118
|
+
/** Called after sign out */
|
|
119
|
+
onSignOut?: () => void;
|
|
120
|
+
/** Called on auth error */
|
|
121
|
+
onError?: (error: Error, code?: string) => void;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ============ Context Value ============
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Value provided by AuthProvider context
|
|
128
|
+
*/
|
|
129
|
+
export interface AuthContextValue {
|
|
130
|
+
user: AuthUser | null;
|
|
131
|
+
loading: boolean;
|
|
132
|
+
error: string | null;
|
|
133
|
+
isAuthenticated: boolean;
|
|
134
|
+
isAnonymous: boolean;
|
|
135
|
+
|
|
136
|
+
// Auth methods
|
|
137
|
+
signInWithGoogle: () => Promise<void>;
|
|
138
|
+
signInWithApple: () => Promise<void>;
|
|
139
|
+
signInWithEmail: (email: string, password: string) => Promise<void>;
|
|
140
|
+
signUpWithEmail: (
|
|
141
|
+
email: string,
|
|
142
|
+
password: string,
|
|
143
|
+
displayName?: string
|
|
144
|
+
) => Promise<void>;
|
|
145
|
+
resetPassword: (email: string) => Promise<void>;
|
|
146
|
+
signOut: () => Promise<void>;
|
|
147
|
+
signInAnonymously: () => Promise<void>;
|
|
148
|
+
|
|
149
|
+
// Error management
|
|
150
|
+
clearError: () => void;
|
|
151
|
+
|
|
152
|
+
// Texts (for child components)
|
|
153
|
+
texts: AuthTexts;
|
|
154
|
+
|
|
155
|
+
// Provider config (for child components)
|
|
156
|
+
providerConfig: AuthProvidersConfig;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============ Component Props ============
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Props for AuthProvider component
|
|
163
|
+
*/
|
|
164
|
+
export interface AuthProviderProps {
|
|
165
|
+
children: ReactNode;
|
|
166
|
+
/** Provider configuration */
|
|
167
|
+
providerConfig: AuthProvidersConfig;
|
|
168
|
+
/** All text strings for i18n */
|
|
169
|
+
texts: AuthTexts;
|
|
170
|
+
/** Firebase error messages for i18n */
|
|
171
|
+
errorTexts: AuthErrorTexts;
|
|
172
|
+
/** Event callbacks */
|
|
173
|
+
callbacks?: AuthCallbacks;
|
|
174
|
+
/** Custom error message resolver (takes precedence over errorTexts) */
|
|
175
|
+
resolveErrorMessage?: (code: string) => string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Auth UI mode
|
|
180
|
+
*/
|
|
181
|
+
export type AuthMode =
|
|
182
|
+
| 'select'
|
|
183
|
+
| 'email-signin'
|
|
184
|
+
| 'email-signup'
|
|
185
|
+
| 'forgot-password';
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Props for AuthScreen component (full-screen auth flow)
|
|
189
|
+
*/
|
|
190
|
+
export interface AuthScreenProps {
|
|
191
|
+
/** Initial mode to show */
|
|
192
|
+
initialMode?: AuthMode;
|
|
193
|
+
/** Custom class name */
|
|
194
|
+
className?: string;
|
|
195
|
+
/** Which providers to show (defaults to providerConfig) */
|
|
196
|
+
providers?: AuthProviderType[];
|
|
197
|
+
/** Show title header (default: true) */
|
|
198
|
+
showTitle?: boolean;
|
|
199
|
+
/** Custom title (overrides texts) */
|
|
200
|
+
title?: string;
|
|
201
|
+
/** Callback when auth mode changes */
|
|
202
|
+
onModeChange?: (mode: AuthMode) => void;
|
|
203
|
+
/** Callback when auth succeeds */
|
|
204
|
+
onSuccess?: () => void;
|
|
205
|
+
/** Optional tracking callback */
|
|
206
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
207
|
+
/** Optional tracking label */
|
|
208
|
+
trackingLabel?: string;
|
|
209
|
+
/** Optional component name for tracking */
|
|
210
|
+
componentName?: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Props for AuthInline component (inline auth flow)
|
|
215
|
+
*/
|
|
216
|
+
export interface AuthInlineProps {
|
|
217
|
+
/** Initial mode to show */
|
|
218
|
+
initialMode?: AuthMode;
|
|
219
|
+
/** Custom class name */
|
|
220
|
+
className?: string;
|
|
221
|
+
/** Which providers to show (defaults to providerConfig) */
|
|
222
|
+
providers?: AuthProviderType[];
|
|
223
|
+
/** Show title header (default: true) */
|
|
224
|
+
showTitle?: boolean;
|
|
225
|
+
/** Custom title (overrides texts) */
|
|
226
|
+
title?: string;
|
|
227
|
+
/** Callback when auth mode changes */
|
|
228
|
+
onModeChange?: (mode: AuthMode) => void;
|
|
229
|
+
/** Callback when auth succeeds */
|
|
230
|
+
onSuccess?: () => void;
|
|
231
|
+
/** Card style variant */
|
|
232
|
+
variant?: 'card' | 'flat' | 'bordered';
|
|
233
|
+
/** Optional tracking callback */
|
|
234
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
235
|
+
/** Optional tracking label */
|
|
236
|
+
trackingLabel?: string;
|
|
237
|
+
/** Optional component name for tracking */
|
|
238
|
+
componentName?: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Custom menu item for AuthAction dropdown
|
|
243
|
+
*/
|
|
244
|
+
export interface AuthMenuItem {
|
|
245
|
+
/** Unique identifier */
|
|
246
|
+
id: string;
|
|
247
|
+
/** Display label */
|
|
248
|
+
label: string;
|
|
249
|
+
/** Press handler */
|
|
250
|
+
onPress: () => void;
|
|
251
|
+
/** Optional icon */
|
|
252
|
+
icon?: ReactNode;
|
|
253
|
+
/** Show divider after this item */
|
|
254
|
+
dividerAfter?: boolean;
|
|
255
|
+
/** Disabled state */
|
|
256
|
+
disabled?: boolean;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Props for AuthAction component (header component)
|
|
261
|
+
*/
|
|
262
|
+
export interface AuthActionProps {
|
|
263
|
+
/** Custom class name */
|
|
264
|
+
className?: string;
|
|
265
|
+
/** Button variant when not logged in */
|
|
266
|
+
loginButtonVariant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
267
|
+
/** Button size */
|
|
268
|
+
size?: 'sm' | 'md' | 'lg';
|
|
269
|
+
/** Custom login button content */
|
|
270
|
+
loginButtonContent?: ReactNode;
|
|
271
|
+
/** Avatar size in pixels (default: 32) */
|
|
272
|
+
avatarSize?: number;
|
|
273
|
+
/** Custom menu items (rendered above logout) */
|
|
274
|
+
menuItems?: AuthMenuItem[];
|
|
275
|
+
/** Show user info section in menu (default: true) */
|
|
276
|
+
showUserInfo?: boolean;
|
|
277
|
+
/** Custom user info renderer */
|
|
278
|
+
renderUserInfo?: (user: AuthUser) => ReactNode;
|
|
279
|
+
/** Custom avatar renderer */
|
|
280
|
+
renderAvatar?: (user: AuthUser) => ReactNode;
|
|
281
|
+
/** Callback when login button pressed */
|
|
282
|
+
onLoginPress?: () => void | boolean;
|
|
283
|
+
/** Callback when logout pressed */
|
|
284
|
+
onLogoutPress?: () => void;
|
|
285
|
+
/** Optional tracking callback */
|
|
286
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
287
|
+
/** Optional tracking label */
|
|
288
|
+
trackingLabel?: string;
|
|
289
|
+
/** Optional component name for tracking */
|
|
290
|
+
componentName?: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Props for Avatar component
|
|
295
|
+
*/
|
|
296
|
+
export interface AvatarProps {
|
|
297
|
+
/** User to display avatar for */
|
|
298
|
+
user: AuthUser;
|
|
299
|
+
/** Size in pixels (default: 32) */
|
|
300
|
+
size?: number;
|
|
301
|
+
/** Custom class name */
|
|
302
|
+
className?: string;
|
|
303
|
+
/** Press handler */
|
|
304
|
+
onPress?: () => void;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Props for internal AuthContent component
|
|
309
|
+
*/
|
|
310
|
+
export interface AuthContentProps {
|
|
311
|
+
/** Current auth mode */
|
|
312
|
+
mode: AuthMode;
|
|
313
|
+
/** Mode change handler */
|
|
314
|
+
onModeChange: (mode: AuthMode) => void;
|
|
315
|
+
/** Override providers */
|
|
316
|
+
providers?: AuthProviderType[];
|
|
317
|
+
/** Success callback */
|
|
318
|
+
onSuccess?: () => void;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Props for form components
|
|
323
|
+
*/
|
|
324
|
+
export interface EmailSignInFormProps {
|
|
325
|
+
onSwitchToSignUp: () => void;
|
|
326
|
+
onSwitchToForgotPassword: () => void;
|
|
327
|
+
onSuccess?: () => void;
|
|
328
|
+
/** Optional tracking callback */
|
|
329
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
330
|
+
/** Optional tracking label */
|
|
331
|
+
trackingLabel?: string;
|
|
332
|
+
/** Optional component name for tracking */
|
|
333
|
+
componentName?: string;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface EmailSignUpFormProps {
|
|
337
|
+
onSwitchToSignIn: () => void;
|
|
338
|
+
onSuccess?: () => void;
|
|
339
|
+
/** Optional tracking callback */
|
|
340
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
341
|
+
/** Optional tracking label */
|
|
342
|
+
trackingLabel?: string;
|
|
343
|
+
/** Optional component name for tracking */
|
|
344
|
+
componentName?: string;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export interface ForgotPasswordFormProps {
|
|
348
|
+
onSwitchToSignIn: () => void;
|
|
349
|
+
/** Optional tracking callback */
|
|
350
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
351
|
+
/** Optional tracking label */
|
|
352
|
+
trackingLabel?: string;
|
|
353
|
+
/** Optional component name for tracking */
|
|
354
|
+
componentName?: string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Props for ProviderButtons component
|
|
359
|
+
*/
|
|
360
|
+
export interface ProviderButtonsProps {
|
|
361
|
+
providers: AuthProviderType[];
|
|
362
|
+
onEmailPress: () => void;
|
|
363
|
+
/** Optional tracking callback */
|
|
364
|
+
onTrack?: (data: AuthTrackingData) => void;
|
|
365
|
+
/** Optional tracking label */
|
|
366
|
+
trackingLabel?: string;
|
|
367
|
+
/** Optional component name for tracking */
|
|
368
|
+
componentName?: string;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ============ Tracking Types ============
|
|
372
|
+
|
|
373
|
+
/** Tracking data for auth component actions */
|
|
374
|
+
export interface AuthTrackingData {
|
|
375
|
+
action:
|
|
376
|
+
| 'login_press'
|
|
377
|
+
| 'logout_press'
|
|
378
|
+
| 'provider_press'
|
|
379
|
+
| 'form_submit'
|
|
380
|
+
| 'switch_mode';
|
|
381
|
+
trackingLabel?: string;
|
|
382
|
+
componentName?: string;
|
|
383
|
+
}
|