Skip to content

Commit 022b05e

Browse files
authored
Merge pull request #58 from PureSwift/fix/sheet-detents
Fix sheets ignoring their detents
2 parents 65bc4c8 + 9c7b42f commit 022b05e

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

AndroidSwiftUICore/Tests/AndroidSwiftUICoreTests/NavigationTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,34 @@ struct NavigationTests {
226226
#expect(host.callbacks.callback(for: tap) != nil)
227227
}
228228

229+
@Test("A sheet carries its detents, and none by default")
230+
func sheetDetents() {
231+
struct Screen: View {
232+
@State var shown = true
233+
var body: some View {
234+
Button("Show") { shown = true }
235+
.sheet(isPresented: $shown) {
236+
Text("body").presentationDetents([.medium])
237+
}
238+
}
239+
}
240+
let node = ViewHost(Screen()).evaluate()
241+
let sheet = node.children.first { $0.type == "Sheet" }
242+
#expect(sheet?.props["detents"] == .array([.string("medium")]))
243+
244+
// no detents declared: the interpreter reads that as a full-height sheet
245+
struct Plain: View {
246+
@State var shown = true
247+
var body: some View {
248+
Button("Show") { shown = true }
249+
.sheet(isPresented: $shown) { Text("body") }
250+
}
251+
}
252+
let plain = ViewHost(Plain()).evaluate()
253+
let plainSheet = plain.children.first { $0.type == "Sheet" }
254+
#expect(plainSheet?.props["detents"] == .array([]))
255+
}
256+
229257
@Test("TabView emits tabs with their item labels and selection")
230258
func tabs() {
231259
struct Screen: View {

Demo/swiftui/src/commonMain/kotlin/com/pureswift/swiftui/Render.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
9090
import androidx.compose.material3.Icon
9191
import androidx.compose.material3.IconButton
9292
import androidx.compose.material3.ModalBottomSheet
93+
import androidx.compose.material3.rememberModalBottomSheetState
9394
import androidx.compose.material3.NavigationBar
9495
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
9596
import androidx.compose.material3.NavigationBarItem
@@ -1719,8 +1720,25 @@ private fun RenderSheetsAndAlerts(screen: ViewNode?) {
17191720
when (child.type) {
17201721
"Sheet" -> {
17211722
val onDismiss = child.long("onDismiss")
1722-
ModalBottomSheet(onDismissRequest = { onDismiss?.let { SwiftBridge.sink.invokeVoid(it) } }) {
1723-
child.children.firstOrNull()?.let { Render(it) }
1723+
// Detents were emitted but never read, so every sheet wrapped its
1724+
// content and a "full-size" sheet came up as a short strip.
1725+
val detents = child.stringArray("detents")
1726+
val medium = detents.contains("medium")
1727+
val large = detents.isEmpty() || detents.contains("large")
1728+
ModalBottomSheet(
1729+
onDismissRequest = { onDismiss?.let { SwiftBridge.sink.invokeVoid(it) } },
1730+
// with no medium detent there is no partial stop to rest at
1731+
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = !medium),
1732+
) {
1733+
// A Material sheet is only as tall as its content, so one that
1734+
// should own the screen has to be told to fill it.
1735+
val height = when {
1736+
medium && !large -> Modifier.fillMaxHeight(0.5f)
1737+
else -> Modifier.fillMaxHeight()
1738+
}
1739+
Box(modifier = height) {
1740+
child.children.firstOrNull()?.let { Render(it) }
1741+
}
17241742
}
17251743
}
17261744
"Alert" -> RenderAlert(child)

0 commit comments

Comments
 (0)