Skip to content

Commit 5c02584

Browse files
committed
Add a common BoxWithConstraints layout composable
It has been tested manually in an internal project on JVM desktop, but not on JS DOM yet. Since the APIs provided, especially those members of `BoxWithConstraintsScope`, are a subset of the corresponding `androidx.compose` ones, also consider moving it out of the `ext` package. The counterargument is that `minWidth` and `minHeight` of `androidx.compose.foundation.layout.BoxWithConstraintsScope` seem not possible to be supported on JS DOM, which is the reason why it's still kept in the `ext` package. Add a `CommonModifier` typealias BTW.
1 parent 93bdf70 commit 5c02584

File tree

5 files changed

+113
-1
lines changed

5 files changed

+113
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ This project is still in development and has not reached the stable state yet. S
3030
- `Row` (via flexbox on JS, based on Kobweb)
3131
- `Spacer`
3232

33+
###### `ext` layouts
34+
35+
- `BoxWithConstraints`
36+
3337
##### Lazy
3438

3539
- `LazyColumn` (via flexbox on JS, based on Kobweb)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.huanshankeji.compose.foundation.layout.ext
2+
3+
import androidx.compose.foundation.layout.BoxScope
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.Stable
6+
import androidx.compose.ui.unit.Dp
7+
import com.huanshankeji.compose.foundation.ExperimentalFoundationApi
8+
import com.huanshankeji.compose.ui.Alignment
9+
import com.huanshankeji.compose.ui.Modifier
10+
11+
@ExperimentalFoundationApi
12+
@Composable
13+
actual fun BoxWithConstraints(
14+
modifier: Modifier,
15+
contentAlignment: Alignment,
16+
content: @Composable BoxWithConstraintsScope.() -> Unit
17+
) =
18+
androidx.compose.foundation.layout.BoxWithConstraints(
19+
modifier.platformModifier, contentAlignment.platformAlignment/*, false*/
20+
) {
21+
BoxWithConstraintsScopeImpl(this, maxWidth, maxHeight).content()
22+
}
23+
24+
@Stable
25+
class BoxWithConstraintsScopeImpl(
26+
override val platformBoxScope: BoxScope,
27+
override val maxWidth: Dp,
28+
override val maxHeight: Dp
29+
) : BoxWithConstraintsScope
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.huanshankeji.compose.foundation.layout.ext
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.Stable
5+
import androidx.compose.ui.unit.Dp
6+
import com.huanshankeji.compose.foundation.ExperimentalFoundationApi
7+
import com.huanshankeji.compose.foundation.layout.BoxScope
8+
import com.huanshankeji.compose.ui.Alignment
9+
import com.huanshankeji.compose.ui.Modifier
10+
11+
// copied and adapted from `androidx.compose.foundation.layout`
12+
13+
@ExperimentalFoundationApi
14+
@Composable
15+
//@UiComposable
16+
expect fun BoxWithConstraints(
17+
modifier: Modifier = Modifier,
18+
contentAlignment: Alignment = Alignment.TopStart,
19+
//propagateMinConstraints: Boolean = false,
20+
content: @Composable /*@UiComposable*/ BoxWithConstraintsScope.() -> Unit
21+
)
22+
23+
@Stable
24+
interface BoxWithConstraintsScope : BoxScope {
25+
val maxWidth: Dp
26+
val maxHeight: Dp
27+
}

compose-multiplatform-common/src/commonMain/kotlin/com/huanshankeji/compose/ui/Modifier.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,10 @@ expect interface Modifier {
55
open infix fun then(other: Modifier): Modifier
66
interface Element : Modifier
77
companion object : Modifier
8-
}
8+
}
9+
10+
/**
11+
* This serves as a shortcut for code completion and an alternative name when you prefer another type taking the name `Modifier` in a file.
12+
* In most cases, it's recommended to use [Modifier] directly.
13+
*/
14+
typealias CommonModifier = Modifier
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.huanshankeji.compose.foundation.layout.ext
2+
3+
import androidx.compose.runtime.*
4+
import androidx.compose.ui.unit.Dp
5+
import androidx.compose.ui.unit.dp
6+
import com.huanshankeji.compose.foundation.ExperimentalFoundationApi
7+
import com.huanshankeji.compose.foundation.layout.Box
8+
import com.huanshankeji.compose.ui.Alignment
9+
import com.huanshankeji.compose.ui.Modifier
10+
import com.varabyte.kobweb.compose.foundation.layout.BoxScope
11+
import com.varabyte.kobweb.compose.ui.attrsModifier
12+
13+
@ExperimentalFoundationApi
14+
@Composable
15+
actual fun BoxWithConstraints(
16+
modifier: Modifier,
17+
contentAlignment: Alignment,
18+
content: @Composable BoxWithConstraintsScope.() -> Unit
19+
) {
20+
var clientSize by remember { mutableStateOf<ClientSize?>(null) }
21+
Box(
22+
Modifier.platformModify {
23+
attrsModifier {
24+
ref {
25+
clientSize = ClientSize(it.clientWidth, it.clientHeight)
26+
onDispose { clientSize = null }
27+
}
28+
}
29+
}.then(modifier),
30+
contentAlignment
31+
) {
32+
clientSize?.let {
33+
// TODO extra conversions might be needed in some cases when converting to `dp`
34+
BoxWithConstraintsScopeImpl(platformBoxScope, it.clientWidth.dp, it.clientHeight.dp).content()
35+
}
36+
}
37+
}
38+
39+
@Stable
40+
class BoxWithConstraintsScopeImpl(
41+
override val platformBoxScope: BoxScope,
42+
override val maxWidth: Dp,
43+
override val maxHeight: Dp
44+
) : BoxWithConstraintsScope
45+
46+
private class ClientSize(val clientWidth: Int, val clientHeight: Int)

0 commit comments

Comments
 (0)