Skip to content

Commit d993761

Browse files
authored
Merge pull request #51 from huanshankeji/box-with-constraints-react-to-size-changes-js-dom
Fix JS DOM display issues in `BoxWithConstraints` and `com.huanshankeji.compose.material2.ext.TopAppBarScaffold`
2 parents a7ea2bd + d945849 commit d993761

File tree

6 files changed

+65
-10
lines changed

6 files changed

+65
-10
lines changed

common/src/commonMain/kotlin/com/huanshankeji/compose/foundation/Scroll.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.huanshankeji.compose.foundation
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.Stable
5+
import com.huanshankeji.compose.ExperimentalApi
56
import com.huanshankeji.compose.foundation.layout.BoxScope
67
import com.huanshankeji.compose.ui.Alignment
78
import com.huanshankeji.compose.ui.Modifier
@@ -24,6 +25,7 @@ See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop.
2425
* it applies to the target as a whole on `androidx` targets, but applies to its content on JS DOM.
2526
* For consistency on different platforms, [VerticalScrollBox] is recommended over this modifier.
2627
*/
28+
@ExperimentalApi
2729
expect fun Modifier.verticalScroll(
2830
state: ScrollState
2931
/*
@@ -37,6 +39,7 @@ expect fun Modifier.verticalScroll(
3739
* For consistency on different platforms, [HorizontalScrollBox] is recommended over this modifier.
3840
* @see verticalScroll
3941
*/
42+
@ExperimentalApi
4043
expect fun Modifier.horizontalScroll(state: ScrollState): Modifier
4144

4245
@Composable

common/src/commonMain/kotlin/com/huanshankeji/compose/ui/unit/ext/DpOrPercentage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.huanshankeji.compose.ui.unit.ext
22

33
import androidx.annotation.IntRange
4+
import com.huanshankeji.compose.ExperimentalApi
45

56
// not used yet
7+
@ExperimentalApi
68
sealed class DpOrPercentage {
79
class Dp(val dp: androidx.compose.ui.unit.Dp) : DpOrPercentage()
810
class Percentage(@IntRange(0, 100) val percentage: Int) : DpOrPercentage()

common/src/jsMain/kotlin/com/huanshankeji/compose/foundation/Scroll.js.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ actual object ScrollState
3434
actual fun Modifier.verticalScroll(state: ScrollState): Modifier =
3535
platformModify { verticalScroll() }
3636

37-
3837
actual fun Modifier.horizontalScroll(state: ScrollState): Modifier =
3938
platformModify { horizontalScroll() }
4039

common/src/jsMain/kotlin/com/huanshankeji/compose/foundation/layout/ext/BoxWithConstraints.js.kt

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.huanshankeji.compose.foundation.ExperimentalFoundationApi
77
import com.huanshankeji.compose.foundation.layout.Box
88
import com.huanshankeji.compose.ui.Alignment
99
import com.huanshankeji.compose.ui.Modifier
10+
import com.varabyte.kobweb.browser.dom.observers.ResizeObserver
1011
import com.varabyte.kobweb.compose.foundation.layout.BoxScope
1112
import com.varabyte.kobweb.compose.ui.attrsModifier
1213

@@ -17,16 +18,41 @@ actual fun BoxWithConstraints(
1718
contentAlignment: Alignment,
1819
content: @Composable BoxWithConstraintsScope.() -> Unit
1920
) {
21+
// `DpClientSize.unspecified` instead of null can be used by default to prevent the content from not rendering when `clientSize` is not set
2022
var clientSize by remember { mutableStateOf<ClientSize?>(null) }
23+
// `DivBox` doesn't work here either, so it should not be Kobweb's problem.
2124
Box(
22-
Modifier.platformModify {
23-
attrsModifier {
24-
ref {
25-
clientSize = ClientSize(it.clientWidth, it.clientHeight)
26-
onDispose { clientSize = null }
25+
Modifier.fillMaxSizeStretch()
26+
.platformModify {
27+
attrsModifier {
28+
ref {
29+
//console.log("Initial client size: ${it.clientWidth}, ${it.clientHeight}")
30+
//clientSize = ClientSize(it.clientWidth, it.clientHeight)
31+
val resizeObserver = ResizeObserver { entries, _ ->
32+
val element = entries.single().target
33+
34+
/*
35+
console.log("width: ${element.clientWidth}, height: ${element.clientHeight}")
36+
console.log(entries.first().contentBoxSize.first())
37+
console.log(entries.first().borderBoxSize.first())
38+
console.log(entries.first().devicePixelContentBoxSize.first()) // If there is zoom this one is different from the 2 above.
39+
*/
40+
41+
with(element) {
42+
//console.log("width: $clientWidth, height: $clientHeight")
43+
clientSize = ClientSize(clientWidth, clientHeight)
44+
}
45+
}
46+
resizeObserver.observe(it)
47+
48+
onDispose {
49+
//resizeObserver.unobserve(it)
50+
resizeObserver.disconnect()
51+
clientSize = null
52+
}
53+
}
2754
}
2855
}
29-
}.fillMaxSizeStretch()
3056
.then(modifier),
3157
contentAlignment
3258
) {
@@ -45,3 +71,13 @@ class BoxWithConstraintsScopeImpl(
4571
) : BoxWithConstraintsScope
4672

4773
private class ClientSize(val clientWidth: Int, val clientHeight: Int)
74+
75+
// removed if not used
76+
/**
77+
* Made in [Dp] so [Dp.Unspecified] can be used.
78+
*/
79+
private class DpClientSize(val clientWidth: Dp, val clientHeight: Dp) {
80+
companion object {
81+
val unspecified = DpClientSize(Dp.Unspecified, Dp.Unspecified)
82+
}
83+
}

material2/src/jsMain/kotlin/com/huanshankeji/compose/material2/ext/TopAppBarScaffold.js.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ actual fun TopAppBarScaffold(
121121
actions,
122122
Modifier.weight(1f).fillMaxWidthStretch()
123123
) {
124+
// This part has a lot of nested `Div`s but works. Do not change unless you are sure that expected behavior is not broken.
125+
124126
// The content gets hidden behind the top app bar if this div is not added.
125127
Div({
126128
style {
@@ -134,9 +136,16 @@ actual fun TopAppBarScaffold(
134136
//overflow(Overflow.Auto) // This seems not needed. TODO remove if confirmed to be not needed
135137
}
136138
}) {
137-
// see `ScaffoldLayoutWithMeasureFix`
138-
val innerPadding = PaddingValues()
139-
content(innerPadding)
139+
// This nested `Div` is here so that a child using `fillMaxSizeStretch` works properly. `fillMaxSizeStretch` seems buggy when used directly in the `position: absolute` parent.
140+
Div({
141+
style {
142+
height(100.percent)
143+
}
144+
}) {
145+
// see `ScaffoldLayoutWithMeasureFix`
146+
val innerPadding = PaddingValues()
147+
content(innerPadding)
148+
}
140149
}
141150

142151
floatingActionButton?.let { fabWithPosition(it) }

material3/src/jsMain/kotlin/com/huanshankeji/compose/material3/lazy/ext/List.js.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ actual class ListScope(val mdListScope: MdListScope) {
9090

9191
actual class ItemScope(val mdListItemScope: MdListItemScope)
9292

93+
/*
94+
@Composable
95+
fun PrimitiveList() =
96+
TODO() as Unit
97+
*/
98+
9399
@Composable
94100
actual fun List(
95101
modifier: Modifier,

0 commit comments

Comments
 (0)