Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BorderStyle #48

Merged
merged 9 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.moriatsushi.compose.stylesheet.surface

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.isSpecified
import com.moriatsushi.compose.stylesheet.StyleSheet
import com.moriatsushi.compose.stylesheet.border.BorderStyle
import com.moriatsushi.compose.stylesheet.component.Component
import com.moriatsushi.compose.stylesheet.component.componentCommonStyle
import com.moriatsushi.compose.stylesheet.content.ContentStyle
Expand Down Expand Up @@ -38,7 +38,7 @@ fun Surface(
tags: TagModifier<SurfaceStyle> = TagModifier(),
background: Color = Color.Unspecified,
shape: Shape? = null,
border: BorderStroke? = null,
border: BorderStyle? = null,
contentColor: Color = Color.Unspecified,
surfaceStyle: SurfaceStyle = SurfaceStyle.Default,
content: @Composable () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,9 @@
package com.moriatsushi.compose.stylesheet

import com.moriatsushi.compose.stylesheet.token.Token
import com.moriatsushi.compose.stylesheet.token.TokenSetter

/**
* An interface for building a [style][T].
*/
interface StyleBuilder<T> {
/**
* Sets the given [token] to [this].
*/
operator fun <T> TokenSetter<T>.plusAssign(token: Token<T>?) {
if (token != null) {
this.token = token
}
}

/**
* Sets the given [value] to [this].
*/
operator fun <T> TokenSetter<T>.plusAssign(value: T) {
this.token = Token(value)
}

/**
* Merges this style with the given [other] style.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.moriatsushi.compose.stylesheet.border

import androidx.compose.foundation.BorderStroke
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi
import com.moriatsushi.compose.stylesheet.graphics.BrushSetterCallback
import com.moriatsushi.compose.stylesheet.graphics.BrushStyle
import com.moriatsushi.compose.stylesheet.token.TokenSetterCallback

class BorderSetter @StyleSheetComponentApi constructor() {
@StyleSheetComponentApi
var value: BorderStyle? = null
private set

/**
* A width of the border.
*/
val width: TokenSetterCallback<Dp> = TokenSetterCallback {
value = value?.copy(width = it) ?: BorderStyle(width = it)
}

/**
* A brush of the border.
*/
val brush: BrushSetterCallback = BrushSetterCallback {
value = value?.copy(brush = it) ?: BorderStyle(brush = it)
}

/**
* A color of the border.
*/
val color: TokenSetterCallback<Color> = TokenSetterCallback {
brush += BrushStyle(it)
}

operator fun plusAssign(border: BorderStyle?) {
if (border != null) {
value = border
}
}

operator fun plusAssign(border: BorderStroke) {
this.value = BorderStyle(border)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.moriatsushi.compose.stylesheet.border

import androidx.compose.foundation.BorderStroke
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.unit.Dp
import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi
import com.moriatsushi.compose.stylesheet.graphics.BrushStyle
import com.moriatsushi.compose.stylesheet.token.Token
import com.moriatsushi.compose.stylesheet.token.value

@Immutable
sealed interface BorderStyle {
val width: Token<Dp>
val brush: Token<BrushStyle>

companion object {
val Unspecified: BorderStyle = BorderStyle()
}
}

@Composable
@StyleSheetComponentApi
fun BorderStyle.asBorderStroke(): BorderStroke? =
if (this != BorderStyle.Unspecified) {
BorderStroke(width = width.value, brush = brush.value.asBrush())
} else {
null
}

internal fun BorderStyle.copy(
width: Token<Dp> = this.width,
brush: Token<BrushStyle> = this.brush,
): BorderStyle = BorderStyle(width = width, brush = brush)

internal fun BorderStyle(
width: Token<Dp> = Token(Dp.Unspecified),
brush: Token<BrushStyle> = Token(BrushStyle.Unspecified),
): BorderStyle = BorderStyleImpl(width = width, brush = brush)

internal fun BorderStyle(borderStroke: BorderStroke): BorderStyle =
BorderStyle(width = Token(borderStroke.width), brush = Token(BrushStyle(borderStroke.brush)))

@Immutable
private data class BorderStyleImpl(
override val width: Token<Dp>,
override val brush: Token<BrushStyle>,
) : BorderStyle
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.moriatsushi.compose.stylesheet.component

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.runtime.Composable
Expand All @@ -11,6 +10,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.isSpecified
import com.moriatsushi.compose.stylesheet.border.BorderStyle
import com.moriatsushi.compose.stylesheet.border.asBorderStroke
import com.moriatsushi.compose.stylesheet.component.padding.ComponentPadding
import com.moriatsushi.compose.stylesheet.component.padding.componentPadding
import com.moriatsushi.compose.stylesheet.component.size.ComponentSize
Expand All @@ -28,7 +29,7 @@ data class ComponentCommonStyle internal constructor(
val padding: ComponentPadding? = null,
internal val background: Token<Color>? = null,
internal val shape: Token<Shape?>? = null,
internal val border: Token<BorderStroke?>? = null,
internal val border: BorderStyle? = null,
) {
companion object {
/**
Expand All @@ -52,7 +53,7 @@ fun Modifier.componentCommonStyle(
): Modifier {
val shape = style.shape?.value ?: RectangleShape

val border = style.border?.value
val border = style.border?.asBorderStroke()
val borderModifier = if (border != null) {
Modifier.border(border, shape)
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.moriatsushi.compose.stylesheet.component

import androidx.compose.foundation.BorderStroke
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.moriatsushi.compose.stylesheet.StyleBuilder
import com.moriatsushi.compose.stylesheet.border.BorderSetter
import com.moriatsushi.compose.stylesheet.component.padding.ComponentPadding
import com.moriatsushi.compose.stylesheet.component.padding.PaddingSetter
import com.moriatsushi.compose.stylesheet.component.size.ComponentFillSize
Expand Down Expand Up @@ -177,8 +177,17 @@ abstract class ComponentStyleBuilder<T : ComponentStyle> : StyleBuilder<T> {

/**
* A background border.
*
* Example:
* ```
* border += BorderStroke(1.dp, Color.Black)
* border += BorderStyle.Unspecified // Clear border
* border.width += 1.dp
* border.color += Color.Black
* border.brush += Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
* ```
*/
val border: TokenSetter<BorderStroke?> = TokenSetter()
val border: BorderSetter = BorderSetter()

/**
* A value for filling the component.
Expand Down Expand Up @@ -259,6 +268,6 @@ abstract class ComponentStyleBuilder<T : ComponentStyle> : StyleBuilder<T> {
padding = padding.value,
background = background.token,
shape = shape.token,
border = border.token,
border = border.value,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.moriatsushi.compose.stylesheet.graphics

import androidx.compose.ui.graphics.Brush
import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi
import com.moriatsushi.compose.stylesheet.token.Token

class BrushSetterCallback @StyleSheetComponentApi constructor(
private val onSet: (Token<BrushStyle>) -> Unit,
) {
/**
* Sets the given [token].
*/
operator fun plusAssign(token: Token<BrushStyle>?) {
if (token != null) {
onSet(token)
}
}

/**
* Sets the given [brush].
*/
operator fun plusAssign(brush: BrushStyle) {
onSet(Token(brush))
}

/**
* Sets the given [brush].
*/
operator fun plusAssign(brush: Brush) {
onSet(Token(BrushStyle(brush)))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.moriatsushi.compose.stylesheet.graphics

import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi
import com.moriatsushi.compose.stylesheet.token.Token
import com.moriatsushi.compose.stylesheet.token.value

sealed interface BrushStyle {
@StyleSheetComponentApi
@Composable
fun asBrush(): Brush

companion object {
val Unspecified: BrushStyle = BrushStyle(Color.Unspecified)
}
}

fun BrushStyle(color: Token<Color>): BrushStyle = SolidColorBrush(color = color)

fun BrushStyle(color: Color): BrushStyle = BrushStyle(color = Token(color))

fun BrushStyle(brush: Brush): BrushStyle = BrushHolder(brush = brush)

private data class SolidColorBrush(val color: Token<Color>) : BrushStyle {
@Composable
override fun asBrush(): Brush = SolidColor(color.value)
}

private data class BrushHolder(private val brush: Brush) : BrushStyle {
@Composable
override fun asBrush(): Brush = brush
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ package com.moriatsushi.compose.stylesheet.token
import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi

class TokenSetter<T> @StyleSheetComponentApi constructor() {
@StyleSheetComponentApi
var token: Token<T>? = null
internal set
private set

/**
* Sets the given [token].
*/
operator fun plusAssign(token: Token<T>?) {
if (token != null) {
this.token = token
}
}

/**
* Sets the given [value].
*/
operator fun plusAssign(value: T) {
this.token = Token(value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.moriatsushi.compose.stylesheet.token

import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi

class TokenSetterCallback<T> @StyleSheetComponentApi constructor(
private val onSet: (Token<T>) -> Unit,
) {
/**
* Sets the given [token].
*/
operator fun plusAssign(token: Token<T>?) {
if (token != null) {
onSet(token)
}
}

/**
* Sets the given [value].
*/
operator fun plusAssign(value: T) {
onSet(Token(value))
}
}
Loading