11import { useClerk , useUser } from '@clerk/react' ;
22import { useEffect , useRef , useState } from 'react' ;
3- import type { StyleProp , ViewStyle } from 'react-native' ;
43import { Image , Platform , StyleSheet , Text , TouchableOpacity , View } from 'react-native' ;
54
65import NativeClerkModule from '../specs/NativeClerkModule' ;
@@ -36,65 +35,16 @@ interface NativeUser {
3635/**
3736 * Props for the UserButton component.
3837 */
39- export interface UserButtonProps {
40- /**
41- * Custom style for the button container.
42- */
43- style ?: StyleProp < ViewStyle > ;
44-
45- /**
46- * Callback fired when the user button is pressed.
47- *
48- * This is called immediately when the button is tapped, before the
49- * profile modal is presented. Use this for analytics or custom behavior.
50- */
51- onPress ?: ( ) => void ;
52-
53- /**
54- * Callback fired when the user signs out from the profile modal.
55- *
56- * This is called after:
57- * 1. The native session is cleared
58- * 2. The JS SDK session is cleared
59- *
60- * After this callback, `useAuth()` will return `isSignedIn: false`.
61- */
62- onSignOut ?: ( ) => void ;
63- }
38+ export interface UserButtonProps { }
6439
6540/**
6641 * A pre-built native button component that displays the user's avatar and opens their profile.
6742 *
6843 * `UserButton` renders a circular button showing the user's profile image (or initials if
69- * no image is available). When tapped, it presents the {@link UserProfileView} modal for
70- * account management.
71- *
72- * This component is powered by:
73- * - **iOS**: clerk-ios (SwiftUI) - https://github.com/clerk/clerk-ios
74- * - **Android**: clerk-android (Jetpack Compose) - https://github.com/clerk/clerk-android
75- *
76- * ## Features
77- *
78- * - **Profile Image**: Displays the user's profile photo from their Clerk account
79- * - **Initials Fallback**: Shows user's initials when no profile image is set
80- * - **Profile Modal**: Opens {@link UserProfileView} with full account management
81- * - **Sign Out Handling**: Properly syncs sign-out between native and JS SDKs
44+ * no image is available). When tapped, it presents the native profile management modal.
8245 *
83- * ## Avatar Display
84- *
85- * The button displays the user's avatar in this order of preference:
86- * 1. User's profile image from Clerk (if available)
87- * 2. First letter of first name + first letter of last name
88- * 3. "U" as a fallback
89- *
90- * ## Styling
91- *
92- * The button is 36x36 pixels by default with circular border radius.
93- * You can customize the size using the `style` prop:
94- *
95- * ```tsx
96- * <UserButton style={{ width: 44, height: 44 }} />
97- * ```
46+ * Sign-out is detected automatically and synced with the JS SDK, causing `useAuth()` to
47+ * update reactively. Use `useAuth()` in a `useEffect` to react to sign-out.
9848 *
9949 * @example Basic usage in a header
10050 * ```tsx
@@ -110,29 +60,26 @@ export interface UserButtonProps {
11060 * }
11161 * ```
11262 *
113- * @example With sign-out handling
63+ * @example Reacting to sign-out
11464 * ```tsx
115- * <UserButton
116- * onSignOut={() => router.replace('/sign-in')}
117- * style={{ width: 40, height: 40 }}
118- * />
119- * ```
65+ * import { UserButton } from '@clerk/expo/native';
66+ * import { useAuth } from '@clerk/expo';
12067 *
121- * @example With press tracking
122- * ```tsx
123- * <UserButton
124- * onPress={( ) => analytics.track('profile_opened')}
125- * onSignOut={() => {
126- * analytics.track('signed_out' );
127- * router.replace('/sign-in');
128- * }}
129- * />
68+ * export default function Header() {
69+ * const { isSignedIn } = useAuth();
70+ *
71+ * useEffect(( ) => {
72+ * if (!isSignedIn) router.replace('/sign-in');
73+ * }, [isSignedIn] );
74+ *
75+ * return <UserButton style={{ width: 40, height: 40 }} />;
76+ * }
13077 * ```
13178 *
13279 * @see {@link UserProfileView } The profile view that opens when tapped
13380 * @see {@link https://clerk.com/docs/components/user/user-button } Clerk UserButton Documentation
13481 */
135- export function UserButton ( { onPress , onSignOut , style } : UserButtonProps ) {
82+ export function UserButton ( _props : UserButtonProps ) {
13683 const [ nativeUser , setNativeUser ] = useState < NativeUser | null > ( null ) ;
13784 const presentingRef = useRef ( false ) ;
13885 const clerk = useClerk ( ) ;
@@ -181,8 +128,6 @@ export function UserButton({ onPress, onSignOut, style }: UserButtonProps) {
181128 return ;
182129 }
183130
184- onPress ?.( ) ;
185-
186131 if ( ! isNativeSupported || ! ClerkExpo ?. presentUserProfile ) {
187132 return ;
188133 }
@@ -225,8 +170,6 @@ export function UserButton({ onPress, onSignOut, style }: UserButtonProps) {
225170 }
226171 }
227172 }
228-
229- onSignOut ?.( ) ;
230173 }
231174 } catch {
232175 // Modal was dismissed by the user — not an error
@@ -248,7 +191,7 @@ export function UserButton({ onPress, onSignOut, style }: UserButtonProps) {
248191 // Show fallback when native modules aren't available
249192 if ( ! isNativeSupported || ! ClerkExpo ) {
250193 return (
251- < View style = { [ styles . button , style ] } >
194+ < View style = { styles . button } >
252195 < Text style = { styles . text } > ?</ Text >
253196 </ View >
254197 ) ;
@@ -257,7 +200,7 @@ export function UserButton({ onPress, onSignOut, style }: UserButtonProps) {
257200 return (
258201 < TouchableOpacity
259202 onPress = { handlePress }
260- style = { [ styles . button , style ] }
203+ style = { styles . button }
261204 >
262205 { user ?. imageUrl ? (
263206 < Image
@@ -275,9 +218,8 @@ export function UserButton({ onPress, onSignOut, style }: UserButtonProps) {
275218
276219const styles = StyleSheet . create ( {
277220 button : {
278- width : 36 ,
279- height : 36 ,
280- borderRadius : 18 ,
221+ width : '100%' ,
222+ height : '100%' ,
281223 overflow : 'hidden' ,
282224 } ,
283225 avatar : {
@@ -289,7 +231,6 @@ const styles = StyleSheet.create({
289231 avatarImage : {
290232 width : '100%' ,
291233 height : '100%' ,
292- borderRadius : 18 ,
293234 } ,
294235 avatarText : {
295236 color : 'white' ,
0 commit comments