Skip to content

Commit

Permalink
Add leading icon to TextField and LabelledTextField components
Browse files Browse the repository at this point in the history
  • Loading branch information
edivad1999 committed Oct 3, 2023
1 parent 5d81d41 commit 0a3cb60
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 5 deletions.
4 changes: 4 additions & 0 deletions core/src/main/kotlin/org/jetbrains/jewel/LabelledTextField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fun LabelledTextField(
hint: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
Expand Down Expand Up @@ -72,6 +73,7 @@ fun LabelledTextField(
hint = hint,
placeholder = placeholder,
trailingIcon = trailingIcon,
leadingIcon = leadingIcon,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
Expand Down Expand Up @@ -103,6 +105,7 @@ fun LabelledTextField(
hint: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
Expand Down Expand Up @@ -131,6 +134,7 @@ fun LabelledTextField(
outline = outline,
placeholder = placeholder,
trailingIcon = trailingIcon,
leadingIcon = leadingIcon,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
Expand Down
32 changes: 29 additions & 3 deletions core/src/main/kotlin/org/jetbrains/jewel/TextField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fun TextField(
outline: Outline = Outline.None,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
Expand Down Expand Up @@ -71,6 +72,7 @@ fun TextField(
outline = outline,
placeholder = placeholder,
trailingIcon = trailingIcon,
leadingIcon = leadingIcon,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
Expand All @@ -94,6 +96,7 @@ fun TextField(
readOnly: Boolean = false,
outline: Outline = Outline.None,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
Expand Down Expand Up @@ -132,6 +135,7 @@ fun TextField(
placeholderTextColor = style.colors.placeholder,
placeholder = if (value.text.isEmpty()) placeholder else null,
trailingIcon = trailingIcon,
leadingIcon = leadingIcon,
)
}
}
Expand All @@ -144,10 +148,16 @@ private fun TextFieldDecorationBox(
placeholderTextColor: Color,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
) {
Layout(
modifier = modifier,
content = {
if (leadingIcon != null) {
Box(modifier = Modifier.layoutId(LEADING_ID), contentAlignment = Alignment.Center) {
leadingIcon()
}
}
if (trailingIcon != null) {
Box(modifier = Modifier.layoutId(TRAILING_ID), contentAlignment = Alignment.Center) {
trailingIcon()
Expand Down Expand Up @@ -175,7 +185,11 @@ private fun TextFieldDecorationBox(
// measure trailing icon
val trailingPlaceable = measurables.find { it.layoutId == TRAILING_ID }
?.measure(iconConstraints)

val leadingPlaceable = measurables.find { it.layoutId == LEADING_ID }
?.measure(iconConstraints)
occupiedSpaceHorizontally += trailingPlaceable?.width ?: 0
occupiedSpaceHorizontally += leadingPlaceable?.width ?: 0

val textFieldConstraints = incomingConstraints.offset(
horizontal = -occupiedSpaceHorizontally,
Expand All @@ -188,12 +202,14 @@ private fun TextFieldDecorationBox(

val width = calculateWidth(
trailingPlaceable,
leadingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
incomingConstraints,
)
val height = calculateHeight(
trailingPlaceable,
leadingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
incomingConstraints,
Expand All @@ -204,6 +220,7 @@ private fun TextFieldDecorationBox(
height,
width,
trailingPlaceable,
leadingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
)
Expand All @@ -213,6 +230,7 @@ private fun TextFieldDecorationBox(

private fun calculateWidth(
trailingPlaceable: Placeable?,
leadingPlaceable: Placeable?,
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
constraints: Constraints,
Expand All @@ -221,26 +239,29 @@ private fun calculateWidth(
textFieldPlaceable.width,
placeholderPlaceable?.width ?: 0,
)
val wrappedWidth = middleSection + (trailingPlaceable?.width ?: 0)
val wrappedWidth = middleSection + (trailingPlaceable?.width ?: 0) + (leadingPlaceable?.width ?: 0)
return max(wrappedWidth, constraints.minWidth)
}

private fun calculateHeight(
trailingPlaceable: Placeable?,
leadingPlaceable: Placeable?,
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
constraints: Constraints,
): Int = maxOf(
textFieldPlaceable.height,
placeholderPlaceable?.height ?: 0,
trailingPlaceable?.height ?: 0,
leadingPlaceable?.height ?: 0,
constraints.minHeight,
)

private fun Placeable.PlacementScope.place(
height: Int,
width: Int,
trailingPlaceable: Placeable?,
leadingPlaceable: Placeable?,
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
) {
Expand All @@ -249,20 +270,25 @@ private fun Placeable.PlacementScope.place(
width - trailingPlaceable.width,
Alignment.CenterVertically.align(trailingPlaceable.height, height),
)
leadingPlaceable?.placeRelative(
0,
Alignment.CenterVertically.align(leadingPlaceable.height, height),
)

// placed center vertically
textFieldPlaceable.placeRelative(
0,
leadingPlaceable?.width ?: 0,
Alignment.CenterVertically.align(textFieldPlaceable.height, height),
)

// placed similar to the input text above
placeholderPlaceable?.placeRelative(
0,
leadingPlaceable?.width ?: 0,
Alignment.CenterVertically.align(placeholderPlaceable.height, height),
)
}

private const val PLACEHOLDER_ID = "Placeholder"
private const val TEXT_FIELD_ID = "TextField"
private const val TRAILING_ID = "Trailing"
private const val LEADING_ID = "Leading"
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private fun ComponentShowcase(svgLoader: JewelSvgLoader, resourceLoader: Resourc
Checkboxes()
RadioButtons()
Links()
TextFields()
TextFields(svgLoader, resourceLoader)
TextAreas()
ProgressBar(svgLoader)
ChipsAndTree()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ package org.jetbrains.jewel.samples.standalone.components

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.Icon
import org.jetbrains.jewel.LabelledTextField
import org.jetbrains.jewel.Outline
import org.jetbrains.jewel.SvgLoader
import org.jetbrains.jewel.Text
import org.jetbrains.jewel.TextField
import org.jetbrains.jewel.styling.ResourcePainterProvider

@Composable
fun TextFields() {
fun TextFields(svgLoader: SvgLoader, resourceLoader: ResourceLoader) {
GroupHeader("TextFields")
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
Expand Down Expand Up @@ -59,4 +65,16 @@ fun TextFields() {
placeholder = { Text("Labelled TextField with hint") },
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.Top,
) {
var text by remember { mutableStateOf("With leading icon") }
TextField(text, { text = it }, enabled = true, leadingIcon = {
val searchIcon by remember { ResourcePainterProvider.stateless("icons/search.svg", svgLoader) }.getPainter(
resourceLoader,
)
Icon(searchIcon, "SearchIcon", Modifier.size(16.dp))
})
}
}

0 comments on commit 0a3cb60

Please sign in to comment.