Skip to content

Commit d10dec4

Browse files
swolfandwobsoriano
andauthored
feat(expo): Part 1 - add native logo max height theme option (#9154)
Co-authored-by: Robert Soriano <sorianorobertc@gmail.com>
1 parent 2c7b1b1 commit d10dec4

9 files changed

Lines changed: 78 additions & 6 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@clerk/expo': patch
3+
---
4+
5+
Add a `logoMaxHeight` prop to `AuthView`, allowing Expo apps to control the maximum height of the managed logo on Android and iOS.
6+
7+
Usage:
8+
9+
```tsx
10+
<AuthView logoMaxHeight={64} />
11+
```

packages/expo/android/src/main/java/expo/modules/clerk/ClerkAuthViewModule.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import android.util.Log
55
import androidx.compose.foundation.layout.fillMaxSize
66
import androidx.compose.runtime.Composable
77
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.unit.dp
89
import androidx.lifecycle.ViewModelStore
910
import androidx.lifecycle.ViewModelStoreOwner
1011
import com.clerk.api.Clerk
12+
import com.clerk.api.ui.ClerkDesign
13+
import com.clerk.api.ui.ClerkTheme
1114
import com.clerk.ui.auth.AuthMode
1215
import com.clerk.ui.auth.AuthView
1316
import expo.modules.kotlin.AppContext
@@ -25,6 +28,7 @@ private fun debugLog(tag: String, message: String) {
2528

2629
class ClerkAuthNativeView(context: Context, appContext: AppContext) : ClerkComposeNativeViewHost(context, appContext) {
2730
var isDismissible: Boolean = true
31+
var logoMaxHeight: Float? = null
2832
var mode: String? = null
2933

3034
private val onAuthEvent by EventDispatcher()
@@ -60,7 +64,7 @@ class ClerkAuthNativeView(context: Context, appContext: AppContext) : ClerkCompo
6064

6165
AuthView(
6266
modifier = Modifier.fillMaxSize(),
63-
clerkTheme = Clerk.customTheme,
67+
clerkTheme = authTheme(),
6468
mode = authMode(mode),
6569
isDismissible = isDismissible,
6670
onDismiss = ::sendDismissEvent,
@@ -70,6 +74,13 @@ class ClerkAuthNativeView(context: Context, appContext: AppContext) : ClerkCompo
7074
)
7175
}
7276

77+
private fun authTheme(): ClerkTheme? {
78+
val maxHeight = logoMaxHeight ?: return Clerk.customTheme
79+
val theme = Clerk.customTheme ?: ClerkTheme()
80+
val design = theme.design ?: ClerkDesign()
81+
return theme.copy(design = design.copy(logoMaxHeight = maxHeight.dp))
82+
}
83+
7384
private fun sendEvent(type: String) {
7485
onAuthEvent(mapOf("type" to type))
7586
}
@@ -102,6 +113,10 @@ class ClerkAuthViewModule : Module() {
102113
view.isDismissible = isDismissible
103114
}
104115

116+
Prop("logoMaxHeight") { view: ClerkAuthNativeView, logoMaxHeight: Float? ->
117+
view.logoMaxHeight = logoMaxHeight
118+
}
119+
105120
OnViewDidUpdateProps { view: ClerkAuthNativeView ->
106121
view.setupView()
107122
}

packages/expo/ios/ClerkAuthNativeView.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import UIKit
44
public class ClerkAuthNativeView: ClerkNativeViewHost {
55
private var currentMode: String = "signInOrUp"
66
private var currentDismissible: Bool = true
7+
private var currentLogoMaxHeight: CGFloat?
78
private var didSendDismiss = false
89

910
let onAuthEvent = EventDispatcher()
@@ -22,6 +23,12 @@ public class ClerkAuthNativeView: ClerkNativeViewHost {
2223
setNeedsHostedViewUpdate()
2324
}
2425

26+
func setLogoMaxHeight(_ logoMaxHeight: CGFloat?) {
27+
guard logoMaxHeight != currentLogoMaxHeight else { return }
28+
currentLogoMaxHeight = logoMaxHeight
29+
setNeedsHostedViewUpdate()
30+
}
31+
2532
private func sendAuthEvent(type: ClerkNativeViewEvent) {
2633
onAuthEvent(["type": type.rawValue])
2734
}
@@ -45,6 +52,7 @@ public class ClerkAuthNativeView: ClerkNativeViewHost {
4552
return ClerkNativeBridge.shared.makeAuthViewController(
4653
mode: currentMode,
4754
dismissible: currentDismissible,
55+
logoMaxHeight: currentLogoMaxHeight,
4856
onEvent: { [weak self] event, _ in
4957
if event == .dismissed {
5058
self?.sendDismissIfNeeded()
@@ -68,6 +76,10 @@ public class ClerkAuthViewModule: Module {
6876
Prop("isDismissible") { (view: ClerkAuthNativeView, isDismissible: Bool?) in
6977
view.setDismissible(isDismissible)
7078
}
79+
80+
Prop("logoMaxHeight") { (view: ClerkAuthNativeView, logoMaxHeight: CGFloat?) in
81+
view.setLogoMaxHeight(logoMaxHeight)
82+
}
7183
}
7284
}
7385
}

packages/expo/ios/ClerkNativeBridge.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ final class ClerkNativeBridge {
229229
func makeAuthViewController(
230230
mode: String,
231231
dismissible: Bool,
232+
logoMaxHeight: CGFloat?,
232233
onEvent: @escaping (ClerkNativeViewEvent, [String: Any]) -> Void
233234
) -> UIViewController? {
234235
guard Self.clerkConfigured else { return nil }
@@ -238,7 +239,8 @@ final class ClerkNativeBridge {
238239
mode: Self.authMode(from: mode),
239240
dismissible: dismissible,
240241
lightTheme: lightTheme,
241-
darkTheme: darkTheme
242+
darkTheme: darkTheme,
243+
logoMaxHeight: logoMaxHeight
242244
),
243245
onDismiss: dismissible ? { onEvent(.dismissed, [:]) } : nil
244246
)
@@ -465,20 +467,27 @@ struct ClerkInlineAuthWrapperView: View {
465467
let dismissible: Bool
466468
let lightTheme: ClerkTheme?
467469
let darkTheme: ClerkTheme?
470+
let logoMaxHeight: CGFloat?
468471

469472
@Environment(\.colorScheme) private var colorScheme
470473

471-
private var themedAuthView: some View {
474+
@ViewBuilder private var themedAuthView: some View {
472475
let view = AuthView(mode: mode, isDismissible: dismissible)
473476
.environment(Clerk.shared)
474477
let theme = colorScheme == .dark ? (darkTheme ?? lightTheme) : lightTheme
475-
return Group {
478+
let themedView = Group {
476479
if let theme {
477480
view.environment(\.clerkTheme, theme)
478481
} else {
479482
view
480483
}
481484
}
485+
486+
if let logoMaxHeight {
487+
themedView.clerkAppIcon(maxHeight: logoMaxHeight)
488+
} else {
489+
themedView
490+
}
482491
}
483492

484493
var body: some View {

packages/expo/src/native/AuthView.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ type AuthNativeEvent = NativeSyntheticEvent<Readonly<{ type: string }>>;
3737
*
3838
* @see {@link https://clerk.com/docs/components/authentication/sign-in} Clerk Sign-In Documentation
3939
*/
40-
export function AuthView({ mode = 'signInOrUp', isDismissible = true, onDismiss }: AuthViewProps): ReactElement {
40+
export function AuthView({
41+
mode = 'signInOrUp',
42+
isDismissible = true,
43+
logoMaxHeight,
44+
onDismiss,
45+
}: AuthViewProps): ReactElement {
4146
const handleAuthEvent = useCallback(
4247
(event: AuthNativeEvent) => {
4348
if (event.nativeEvent.type === 'dismissed') {
@@ -64,6 +69,7 @@ export function AuthView({ mode = 'signInOrUp', isDismissible = true, onDismiss
6469
style={{ flex: 1 }}
6570
mode={mode}
6671
isDismissible={isDismissible}
72+
logoMaxHeight={logoMaxHeight}
6773
onAuthEvent={handleAuthEvent}
6874
/>
6975
);

packages/expo/src/native/AuthView.types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export interface AuthViewProps {
3838
*/
3939
isDismissible?: boolean;
4040

41+
/**
42+
* Maximum height of the Clerk application logo, in density-independent pixels.
43+
*
44+
* @default 44
45+
*/
46+
logoMaxHeight?: number;
47+
4148
/**
4249
* Called when the native authentication view requests dismissal.
4350
*

packages/expo/src/native/__tests__/AuthView.test.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { render } from '@testing-library/react';
22
import React from 'react';
3-
import { describe, expect, test, vi } from 'vitest';
3+
import { beforeEach, describe, expect, test, vi } from 'vitest';
44

55
import { AuthView } from '../AuthView';
66

@@ -30,6 +30,16 @@ vi.mock('react-native', () => {
3030
});
3131

3232
describe('AuthView', () => {
33+
beforeEach(() => {
34+
mocks.NativeClerkAuthView.mockClear();
35+
});
36+
37+
test('passes logoMaxHeight to the native auth view', () => {
38+
render(<AuthView logoMaxHeight={64} />);
39+
40+
expect(mocks.NativeClerkAuthView.mock.calls[0]?.[0]).toMatchObject({ logoMaxHeight: 64 });
41+
});
42+
3343
test('calls onDismiss when the native auth view emits dismissed', () => {
3444
const onDismiss = vi.fn();
3545

packages/expo/src/specs/NativeClerkAuthView.android.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type AuthEvent = Readonly<{ type: string }>;
66
interface NativeProps extends ViewProps {
77
mode?: string;
88
isDismissible?: boolean;
9+
logoMaxHeight?: number;
910
onAuthEvent?: (event: NativeSyntheticEvent<AuthEvent>) => void;
1011
}
1112

packages/expo/src/specs/NativeClerkAuthView.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type AuthEvent = Readonly<{ type: string }>;
77
interface NativeProps extends ViewProps {
88
mode?: string;
99
isDismissible?: boolean;
10+
logoMaxHeight?: number;
1011
onAuthEvent?: (event: NativeSyntheticEvent<AuthEvent>) => void;
1112
}
1213

0 commit comments

Comments
 (0)