Skip to content

Commit baa962d

Browse files
committed
Implement borders and colors, and refactor sizes and update the demo
1 parent 8ad4091 commit baa962d

File tree

13 files changed

+246
-50
lines changed

13 files changed

+246
-50
lines changed

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

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

33
//import androidx.compose.ui.Modifier
4-
import com.huanshankeji.compose.ui.unit.NumericSize
5-
import com.huanshankeji.compose.ui.unit.Size
4+
import com.huanshankeji.compose.ui.color.Color
5+
import com.huanshankeji.compose.ui.unit.HeightOrWidth
6+
import com.huanshankeji.compose.ui.unit.Length
7+
import com.huanshankeji.compose.ui.unit.LengthOrPercentage
68

79
typealias NotNullModifierOrAttrs<TElement> = ModifierOrAttrsScope<TElement>.() -> Unit
810
typealias ModifierOrAttrs<TElement> = NotNullModifierOrAttrs<TElement>?
@@ -28,25 +30,50 @@ expect class ModifierOrAttrsScope<out TElement : Element> {
2830
fun style(builder: StyleScope.() -> Unit)
2931
}
3032

33+
/**
34+
* Keep in mind that the functions in this class call functions in
35+
* [org.jetbrains.compose.web.css.StyleScope] and [androidx.compose.ui.Modifier] under the hood
36+
* so their visual results are not consistent.
37+
* As different orders of `Modifier` function calls produce different results,
38+
* different orders of function calls in this class produce different results on desktop and Android.
39+
* They do produce the same results on web as long as no former property is overriden by a latter one,
40+
* as different orders of CSS properties do in the HTML `style` attribute.
41+
*/
3142
expect class StyleScope {
32-
fun margin(value: NumericSize)
33-
fun height(value: Size)
34-
fun width(value: Size)
43+
fun margin(value: LengthOrPercentage)
44+
fun height(value: HeightOrWidth)
45+
fun width(value: HeightOrWidth)
46+
47+
fun backgroundColor(color: Color)
48+
49+
/**
50+
* Currently inconsistent, adds inner border on desktop and Android and outer padding on web.
51+
*/
52+
fun border(width: Length, color: Color)
53+
54+
fun outerBorder(width: Length, color: Color)
55+
56+
// TODO
57+
/*
58+
class CornerSize
59+
60+
fun roundedCornerBorder(width: Length, color: Color, cornerRadius: CornerSize)
61+
*/
3562
}
3663

37-
fun StyleScope.height(value: NumericSize) =
38-
height(Size.Numeric(value))
64+
fun StyleScope.height(value: LengthOrPercentage) =
65+
height(HeightOrWidth.Numeric(value))
3966

40-
fun StyleScope.width(value: NumericSize) =
41-
width(Size.Numeric(value))
67+
fun StyleScope.width(value: LengthOrPercentage) =
68+
width(HeightOrWidth.Numeric(value))
4269

4370
private const val PADDING_MESSAGE =
4471
"This function is a placeholder for code completion. " +
4572
"Use `margin` to add space around the composable, which is equivalent to `Modifier.padding`. " +
4673
"Set `margin` in the inner composable to add inner padding."
4774

4875
@Deprecated(PADDING_MESSAGE)
49-
fun StyleScope.padding(value: NumericSize): Unit =
76+
fun StyleScope.padding(value: LengthOrPercentage): Unit =
5077
throw NotImplementedError(PADDING_MESSAGE)
5178

5279
/*
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.huanshankeji.compose.ui.color
2+
3+
expect class Color
4+
5+
internal fun UByte.alphaToFloatRatio(): Float =
6+
toFloat() / 255
7+
8+
internal fun Float.alphaToUByte(): UByte {
9+
require(this in 0f..1f)
10+
return (this * 255).toInt().toUByte()
11+
}
12+
13+
expect fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: UByte): Color
14+
expect fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: Float): Color
15+
16+
expect fun rgbColor(red: UByte, green: UByte, blue: UByte): Color
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.huanshankeji.compose.ui.color
2+
3+
expect object Colors {
4+
val black: Color
5+
val white: Color
6+
val gray : Color
7+
val red: Color
8+
val green: Color
9+
val blue: Color
10+
}
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.huanshankeji.compose.ui.unit
22

3-
expect abstract class NumericSize
4-
expect class DpOrPx : NumericSize
3+
// Percentage is only supported on JS.
4+
expect sealed interface LengthOrPercentage
5+
expect sealed interface Length : LengthOrPercentage
6+
7+
expect class DpOrPx : Length
58

69
expect val Int.dpOrPx: DpOrPx
710

811

9-
sealed class Size {
10-
class Numeric(val value: NumericSize) : Size()
11-
object FillMax : Size()
12-
object FitContent : Size()
12+
sealed class HeightOrWidth {
13+
class Numeric(val value: LengthOrPercentage) : HeightOrWidth()
14+
object FillMax : HeightOrWidth()
15+
object FitContent : HeightOrWidth()
1316
}

compose-multiplatform-common/src/jsMain/kotlin/com/huanshankeji/compose/ui/ModifierOrAttrsScope.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package com.huanshankeji.compose.ui
22

3-
import com.huanshankeji.compose.ui.unit.NumericSize
4-
import com.huanshankeji.compose.ui.unit.Size
5-
import com.huanshankeji.compose.ui.unit.Size.*
3+
import com.huanshankeji.compose.ui.color.Color
4+
import com.huanshankeji.compose.ui.unit.HeightOrWidth
5+
import com.huanshankeji.compose.ui.unit.HeightOrWidth.*
6+
import com.huanshankeji.compose.ui.unit.Length
7+
import com.huanshankeji.compose.ui.unit.LengthOrPercentage
68
import com.huanshankeji.compose.web.css.FIT_CONTENT
79
import com.huanshankeji.compose.web.css.height
810
import com.huanshankeji.compose.web.css.width
911
import org.jetbrains.compose.web.attributes.AttrsScope
10-
import org.jetbrains.compose.web.css.height
11-
import org.jetbrains.compose.web.css.margin
12-
import org.jetbrains.compose.web.css.percent
13-
import org.jetbrains.compose.web.css.width
12+
import org.jetbrains.compose.web.css.*
1413
import org.jetbrains.compose.web.dom.AttrBuilderContext
1514
import org.w3c.dom.HTMLElement
1615

@@ -28,10 +27,10 @@ actual class ModifierOrAttrsScope<out TElement : Element>(val attrsScope: AttrsS
2827
}
2928

3029
actual class StyleScope(val styleScope: org.jetbrains.compose.web.css.StyleScope) {
31-
actual fun margin(value: NumericSize) =
30+
actual fun margin(value: LengthOrPercentage) =
3231
styleScope.margin(value.platformValue)
3332

34-
actual fun height(value: Size) =
33+
actual fun height(value: HeightOrWidth) =
3534
styleScope.run {
3635
when (value) {
3736
FitContent -> height(FIT_CONTENT)
@@ -40,12 +39,22 @@ actual class StyleScope(val styleScope: org.jetbrains.compose.web.css.StyleScope
4039
}
4140
}
4241

43-
actual fun width(value: Size) =
42+
actual fun width(value: HeightOrWidth) =
4443
styleScope.run {
4544
when (value) {
4645
FitContent -> width(FIT_CONTENT)
4746
FillMax -> width(100.percent)
4847
is Numeric -> width(value.value.platformValue)
4948
}
5049
}
50+
51+
52+
actual fun backgroundColor(color: Color) =
53+
styleScope.backgroundColor(color.platformValue)
54+
55+
actual fun border(width: Length, color: Color) =
56+
styleScope.border(width.platformValue, LineStyle.Solid, color.platformValue)
57+
58+
actual fun outerBorder(width: Length, color: Color) =
59+
border(width, color)
5160
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.huanshankeji.compose.ui.color
2+
3+
import org.jetbrains.compose.web.css.CSSColorValue
4+
import org.jetbrains.compose.web.css.rgb
5+
import org.jetbrains.compose.web.css.rgba
6+
7+
actual class Color(val platformValue: CSSColorValue)
8+
9+
actual fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: UByte): Color =
10+
rgbaColor(red, green, blue, alpha.alphaToFloatRatio())
11+
12+
actual fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: Float): Color =
13+
Color(rgba(red.toInt(), green.toInt(), blue.toInt(), alpha))
14+
15+
actual fun rgbColor(red: UByte, green: UByte, blue: UByte): Color =
16+
Color(rgb(red.toInt(), green.toInt(), blue.toInt()))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.huanshankeji.compose.ui.color
2+
3+
import org.jetbrains.compose.web.css.Color as CssColor
4+
5+
actual object Colors {
6+
actual val black = Color(CssColor.black)
7+
actual val white = Color(CssColor.white)
8+
actual val gray = Color(CssColor.gray)
9+
actual val red = Color(CssColor.red)
10+
actual val green = Color(CssColor.green)
11+
actual val blue = Color(CssColor.blue)
12+
}
Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
package com.huanshankeji.compose.ui.unit
22

3-
import org.jetbrains.compose.web.css.CSSLengthOrPercentageValue
4-
import org.jetbrains.compose.web.css.CSSSizeValue
5-
import org.jetbrains.compose.web.css.CSSUnit
6-
import org.jetbrains.compose.web.css.px
3+
import org.jetbrains.compose.web.css.*
74

8-
actual abstract class NumericSize(val platformValue: CSSLengthOrPercentageValue)
9-
actual class DpOrPx(platformValue: CSSSizeValue<CSSUnit.px>) : NumericSize(platformValue)
5+
// TODO: consider adding a platform value type parameter or making it an interface.
6+
actual sealed interface LengthOrPercentage {
7+
val platformValue: CSSLengthOrPercentageValue
8+
9+
class Impl(override val platformValue: CSSLengthOrPercentageValue) : LengthOrPercentage
10+
}
11+
12+
actual sealed interface Length : LengthOrPercentage {
13+
override val platformValue: CSSLengthValue
14+
15+
class Impl(override val platformValue: CSSLengthValue) : Length
16+
}
17+
18+
// JS only
19+
class Percentage(override val platformValue: CSSPercentageValue) : LengthOrPercentage
20+
21+
22+
actual class DpOrPx(override val platformValue: CSSpxValue) : Length
1023

1124
actual val Int.dpOrPx: DpOrPx
1225
get() = DpOrPx(this.px)

compose-multiplatform-common/src/jvmMain/kotlin/com/huanshankeji/compose/ui/ModifierOrAttrsScopeJvm.kt

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.huanshankeji.compose.ui
22

3-
import androidx.compose.foundation.layout.fillMaxHeight
4-
import androidx.compose.foundation.layout.height
5-
import androidx.compose.foundation.layout.padding
6-
import androidx.compose.foundation.layout.width
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.border
5+
import androidx.compose.foundation.layout.*
76
import androidx.compose.ui.Modifier
8-
import com.huanshankeji.compose.ui.unit.NumericSize
9-
import com.huanshankeji.compose.ui.unit.Size
10-
import com.huanshankeji.compose.ui.unit.Size.*
7+
import com.huanshankeji.compose.ui.color.Color
8+
import com.huanshankeji.compose.ui.unit.HeightOrWidth
9+
import com.huanshankeji.compose.ui.unit.HeightOrWidth.*
10+
import com.huanshankeji.compose.ui.unit.Length
11+
import com.huanshankeji.compose.ui.unit.LengthOrPercentage
12+
import com.huanshankeji.compose.ui.unit.asDpOrPx
1113

1214
fun <TElement : Element> ModifierOrAttrs<TElement>.toModifier(): Modifier =
1315
this?.let {
@@ -35,23 +37,41 @@ actual class ModifierOrAttrsScope<out TElement : Element>(modifier: Modifier) {
3537
}
3638

3739
actual class StyleScope(val modifierOrAttrsScope: ModifierOrAttrsScope<*>) {
38-
actual fun margin(value: NumericSize) = modifierOrAttrsScope.modify {
39-
padding(value.platformValue)
40+
fun modify(block: Modifier.() -> Modifier) =
41+
modifierOrAttrsScope.modify(block)
42+
43+
actual fun margin(value: LengthOrPercentage) = modify {
44+
padding(value.asDpOrPx().platformValue)
4045
}
4146

42-
actual fun height(value: Size) = modifierOrAttrsScope.modify {
47+
actual fun height(value: HeightOrWidth) = modify {
4348
when (value) {
44-
FitContent -> this
49+
FitContent -> this //wrapContentHeight()
4550
FillMax -> fillMaxHeight()
46-
is Numeric -> height(value.value.platformValue)
51+
is Numeric -> height(value.value.asDpOrPx().platformValue)
4752
}
4853
}
4954

50-
actual fun width(value: Size) = modifierOrAttrsScope.modify {
55+
actual fun width(value: HeightOrWidth) = modify {
56+
this@modify.fillMaxWidth()
5157
when (value) {
52-
FitContent -> this
58+
FitContent -> this //wrapContentWidth()
5359
FillMax -> fillMaxHeight()
54-
is Numeric -> width(value.value.platformValue)
60+
is Numeric -> width(value.value.asDpOrPx().platformValue)
5561
}
5662
}
63+
64+
65+
actual fun backgroundColor(color: Color) = modify {
66+
background(color.platformValue)
67+
}
68+
69+
actual fun border(width: Length, color: Color) = modify {
70+
border(width.asDpOrPx().platformValue, color.platformValue)
71+
}
72+
73+
actual fun outerBorder(width: Length, color: Color) {
74+
border(width, color)
75+
margin(width)
76+
}
5777
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.huanshankeji.compose.ui.color
2+
3+
import androidx.compose.ui.graphics.Color as PlatformColor
4+
5+
typealias PlatformColor = androidx.compose.ui.graphics.Color
6+
7+
actual class Color(val platformValue: PlatformColor)
8+
9+
actual fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: UByte): Color =
10+
Color(PlatformColor(red.toInt(), green.toInt(), blue.toInt(), alpha.toInt()))
11+
12+
actual fun rgbaColor(red: UByte, green: UByte, blue: UByte, alpha: Float): Color =
13+
rgbaColor(red, green, blue, alpha.alphaToUByte())
14+
15+
actual fun rgbColor(red: UByte, green: UByte, blue: UByte): Color =
16+
Color(PlatformColor(red.toInt(), green.toInt(), blue.toInt()))

0 commit comments

Comments
 (0)