Skip to content

Commit

Permalink
Fix TextArea layout (#409)
Browse files Browse the repository at this point in the history
* Content was vertically centred, but should top-aligned
* TextAreas didn't respect incoming min constraints
  • Loading branch information
rock3r committed Jun 14, 2024
1 parent ea14724 commit bf5969b
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jetbrains.jewel.samples.standalone.view.component

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -40,16 +41,16 @@ fun TextAreas() {
verticalAlignment = Alignment.Top,
) {
var text1 by remember { mutableStateOf(LOREM_IPSUM) }
TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f))
TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f).fillMaxHeight())

var text2 by remember { mutableStateOf(LOREM_IPSUM) }
TextArea(text2, { text2 = it }, modifier = Modifier.weight(1f), enabled = false)
TextArea(text2, { text2 = it }, modifier = Modifier.weight(1f).fillMaxHeight(), enabled = false)

var text3 by remember { mutableStateOf("") }
TextArea(
text3,
{ text3 = it },
modifier = Modifier.weight(1f),
modifier = Modifier.weight(1f).fillMaxHeight(),
outline = Outline.Error,
placeholder = { Text("Text area with error") },
)
Expand All @@ -58,7 +59,7 @@ fun TextAreas() {
TextArea(
text4,
{ text4 = it },
modifier = Modifier.weight(1f),
modifier = Modifier.weight(1f).fillMaxHeight(),
outline = Outline.Warning,
placeholder = { Text("Text area with warning") },
)
Expand Down
38 changes: 17 additions & 21 deletions ui/src/main/kotlin/org/jetbrains/jewel/ui/component/TextArea.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.jetbrains.jewel.ui.component
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
Expand Down Expand Up @@ -152,7 +153,7 @@ private fun TextAreaDecorationBox(
if (placeholder != null) {
Box(
modifier = Modifier.layoutId(PLACEHOLDER_ID),
contentAlignment = Alignment.CenterStart,
contentAlignment = Alignment.TopStart,
) {
CompositionLocalProvider(
LocalTextStyle provides textStyle.copy(color = placeholderTextColor),
Expand All @@ -164,7 +165,7 @@ private fun TextAreaDecorationBox(

Box(
modifier = Modifier.layoutId(TEXT_AREA_ID),
contentAlignment = Alignment.CenterStart,
contentAlignment = Alignment.TopStart,
propagateMinConstraints = true,
) {
innerTextField()
Expand Down Expand Up @@ -193,43 +194,38 @@ private fun TextAreaDecorationBox(
measurables.find { it.layoutId == PLACEHOLDER_ID }
?.measure(placeholderConstraints)

val width = calculateWidth(textAreaPlaceable, placeholderPlaceable, textAreaConstraints)
val height = calculateHeight(textAreaPlaceable, placeholderPlaceable, verticalPadding, textAreaConstraints)
val width = calculateWidth(textAreaPlaceable, placeholderPlaceable, incomingConstraints)
val height = calculateHeight(textAreaPlaceable, placeholderPlaceable, verticalPadding, incomingConstraints)

layout(width, height) {
place(height, textAreaPlaceable, placeholderPlaceable)
val startPadding = contentPadding.calculateStartPadding(layoutDirection).roundToPx()
val topPadding = contentPadding.calculateTopPadding().roundToPx()

// Placed top-start
textAreaPlaceable.placeRelative(startPadding, topPadding)

// Placed similar to the input text above
placeholderPlaceable?.placeRelative(startPadding, topPadding)
}
}
}

private fun calculateWidth(
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
constraints: Constraints,
incomingConstraints: Constraints,
): Int =
maxOf(textFieldPlaceable.width, placeholderPlaceable?.width ?: 0)
.coerceAtLeast(constraints.minWidth)
.coerceAtLeast(incomingConstraints.minWidth)

private fun calculateHeight(
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
verticalPadding: Int,
constraints: Constraints,
incomingConstraints: Constraints,
): Int {
val textAreaHeight = maxOf(textFieldPlaceable.height, placeholderPlaceable?.height ?: 0)
return (textAreaHeight + verticalPadding).coerceAtLeast(constraints.minHeight)
}

private fun Placeable.PlacementScope.place(
height: Int,
textAreaPlaceable: Placeable,
placeholderPlaceable: Placeable?,
) {
// placed center vertically
textAreaPlaceable.placeRelative(0, Alignment.CenterVertically.align(textAreaPlaceable.height, height))

// placed similar to the input text above
placeholderPlaceable?.placeRelative(0, Alignment.CenterVertically.align(placeholderPlaceable.height, height))
return (textAreaHeight + verticalPadding).coerceAtLeast(incomingConstraints.minHeight)
}

private const val PLACEHOLDER_ID = "Placeholder"
Expand Down

0 comments on commit bf5969b

Please sign in to comment.