@@ -2,19 +2,30 @@ package expo.modules.clerk
22
33import android.content.Context
44import android.util.Log
5+ import androidx.compose.foundation.Canvas
56import androidx.compose.foundation.isSystemInDarkTheme
67import androidx.compose.foundation.layout.Box
78import androidx.compose.foundation.layout.BoxWithConstraints
89import androidx.compose.foundation.layout.fillMaxSize
910import androidx.compose.foundation.layout.fillMaxWidth
1011import androidx.compose.foundation.layout.height
12+ import androidx.compose.foundation.layout.padding
13+ import androidx.compose.foundation.layout.size
14+ import androidx.compose.material3.BottomSheetDefaults
1115import androidx.compose.material3.ExperimentalMaterial3Api
16+ import androidx.compose.material3.IconButton
1217import androidx.compose.material3.ModalBottomSheet
1318import androidx.compose.material3.SheetValue
1419import androidx.compose.material3.rememberModalBottomSheetState
1520import androidx.compose.runtime.Composable
21+ import androidx.compose.ui.Alignment
1622import androidx.compose.ui.Modifier
23+ import androidx.compose.ui.geometry.Offset
1724import androidx.compose.ui.graphics.Color
25+ import androidx.compose.ui.graphics.StrokeCap
26+ import androidx.compose.ui.platform.LocalDensity
27+ import androidx.compose.ui.semantics.contentDescription
28+ import androidx.compose.ui.semantics.semantics
1829import androidx.compose.ui.unit.dp
1930import androidx.lifecycle.ViewModelStore
2031import androidx.lifecycle.ViewModelStoreOwner
@@ -89,32 +100,76 @@ class ClerkAuthNativeView(context: Context, appContext: AppContext) : ClerkCompo
89100 onDismissRequest = ::sendDismissEvent,
90101 sheetState = sheetState,
91102 containerColor = clerkBackgroundColor(),
103+ dragHandle = { SheetDragHandle () },
92104 ) {
93105 BoxWithConstraints (modifier = Modifier .fillMaxSize()) {
94- val authHeight =
95- if (sheetState.currentValue == SheetValue .Expanded ) maxHeight else maxHeight / 2
96-
97- Box (modifier = Modifier .fillMaxWidth().height(authHeight)) {
98- ClerkAuthView ()
106+ val density = LocalDensity .current
107+ val sheetOffsetPx =
108+ runCatching { sheetState.requireOffset() }
109+ .getOrDefault(with (density) { maxHeight.toPx() })
110+ val sheetOffset = with (density) { sheetOffsetPx.toDp() }
111+ val authHeight = (maxHeight - sheetOffset).coerceAtLeast(0 .dp)
112+
113+ if (sheetState.currentValue != SheetValue .Hidden ) {
114+ Box (modifier = Modifier .fillMaxWidth().height(authHeight)) {
115+ ClerkAuthView (showDismissAction = false )
116+ }
99117 }
100118 }
101119 }
102120 }
103121
104122 @Composable
105- private fun ClerkAuthView () {
123+ private fun ClerkAuthView (showDismissAction : Boolean = isDismissible ) {
106124 AuthView (
107125 modifier = Modifier .fillMaxSize(),
108126 clerkTheme = authTheme(),
109127 mode = authMode(mode),
110- isDismissible = isDismissible ,
128+ isDismissible = showDismissAction ,
111129 onDismiss = ::sendDismissEvent,
112130 onAuthComplete = {
113131 sendDismissEvent()
114132 },
115133 )
116134 }
117135
136+ @Composable
137+ @OptIn(ExperimentalMaterial3Api ::class )
138+ private fun SheetDragHandle () {
139+ Box (modifier = Modifier .fillMaxWidth().height(48 .dp)) {
140+ BottomSheetDefaults .DragHandle (modifier = Modifier .align(Alignment .Center ))
141+ if (isDismissible) {
142+ IconButton (
143+ onClick = ::sendDismissEvent,
144+ modifier =
145+ Modifier .align(Alignment .CenterEnd )
146+ .padding(end = 12 .dp)
147+ .semantics { contentDescription = " Close" },
148+ ) {
149+ val color = clerkForegroundColor()
150+ Canvas (modifier = Modifier .size(24 .dp)) {
151+ val inset = 4 .dp.toPx()
152+ val strokeWidth = 2 .dp.toPx()
153+ drawLine(
154+ color = color,
155+ start = Offset (inset, inset),
156+ end = Offset (size.width - inset, size.height - inset),
157+ strokeWidth = strokeWidth,
158+ cap = StrokeCap .Round ,
159+ )
160+ drawLine(
161+ color = color,
162+ start = Offset (size.width - inset, inset),
163+ end = Offset (inset, size.height - inset),
164+ strokeWidth = strokeWidth,
165+ cap = StrokeCap .Round ,
166+ )
167+ }
168+ }
169+ }
170+ }
171+ }
172+
118173 @Composable
119174 private fun clerkBackgroundColor (): Color {
120175 val isDarkMode = isSystemInDarkTheme()
@@ -126,6 +181,17 @@ class ClerkAuthNativeView(context: Context, appContext: AppContext) : ClerkCompo
126181 ? : if (isDarkMode) Color (0xFF131316 ) else Color .White
127182 }
128183
184+ @Composable
185+ private fun clerkForegroundColor (): Color {
186+ val isDarkMode = isSystemInDarkTheme()
187+ val customTheme = Clerk .customTheme
188+ val modeColors = if (isDarkMode) customTheme?.darkColors else customTheme?.lightColors
189+
190+ return modeColors?.foreground
191+ ? : customTheme?.colors?.foreground
192+ ? : if (isDarkMode) Color .White else Color .Black
193+ }
194+
129195 private fun authTheme (): ClerkTheme ? {
130196 val maxHeight = logoMaxHeight ? : return Clerk .customTheme
131197 val theme = Clerk .customTheme ? : ClerkTheme ()
0 commit comments