From e3c6c2c3ba9c40618536eeeaff48095207df333a Mon Sep 17 00:00:00 2001 From: flash159483 Date: Sun, 18 Aug 2024 16:41:02 +0900 Subject: [PATCH] =?UTF-8?q?[FEAT]#111:=20TextField=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/input/WsTextField.kt | 180 +++++++++++------- 1 file changed, 113 insertions(+), 67 deletions(-) diff --git a/designsystem/src/main/kotlin/com/bff/wespot/designsystem/component/input/WsTextField.kt b/designsystem/src/main/kotlin/com/bff/wespot/designsystem/component/input/WsTextField.kt index 81a7c1ff5..6f38472b6 100644 --- a/designsystem/src/main/kotlin/com/bff/wespot/designsystem/component/input/WsTextField.kt +++ b/designsystem/src/main/kotlin/com/bff/wespot/designsystem/component/input/WsTextField.kt @@ -1,5 +1,6 @@ package com.bff.wespot.designsystem.component.input +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -7,18 +8,24 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.selection.LocalTextSelectionColors +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -26,10 +33,13 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusState import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.bff.wespot.designsystem.R @@ -40,6 +50,7 @@ import com.bff.wespot.designsystem.theme.WeSpotTheme import com.bff.wespot.designsystem.theme.WeSpotThemeManager import com.bff.wespot.designsystem.util.OrientationPreviews +@OptIn(ExperimentalMaterial3Api::class) @Composable fun WsTextField( value: String, @@ -55,85 +66,120 @@ fun WsTextField( textFieldType: WsTextFieldType = WsTextFieldType.Normal, ) { var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) } - + val interactionSource = remember { MutableInteractionSource() } LaunchedEffect(value) { if (value != textFieldValueState.text) { textFieldValueState = textFieldValueState.copy(text = value) } } + val colors = OutlinedTextFieldDefaults.colors( + focusedContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, + unfocusedContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, + focusedPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, + unfocusedPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, + focusedBorderColor = if (textFieldType == WsTextFieldType.Message) { + WeSpotThemeManager.colors.cardBackgroundColor + } else { + Primary400 + }, + unfocusedBorderColor = WeSpotThemeManager.colors.cardBackgroundColor, + disabledContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, + disabledPlaceholderColor = Gray400, + disabledBorderColor = WeSpotThemeManager.colors.cardBackgroundColor, + errorBorderColor = WeSpotThemeManager.colors.dangerColor, + errorContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, + errorPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, + ) + Box(modifier = Modifier.wrapContentSize()) { - OutlinedTextField( - modifier = Modifier - .heightIn( - min = textFieldType.minHeight(), - max = textFieldType.maxHeight(), - ) - .fillMaxWidth() - .focusRequester(focusRequester) - .onFocusChanged { focusState -> onFocusChanged(focusState) }, - value = textFieldValueState, - onValueChange = { newTextFieldValue -> - textFieldValueState = newTextFieldValue - onValueChange(newTextFieldValue.text) - }, - isError = isError, - singleLine = singleLine, - readOnly = readOnly, - enabled = textFieldType.isEnabled(), - keyboardOptions = keyBoardOption, - keyboardActions = keyboardActions, - trailingIcon = if (textFieldType.trailingIcon() != null) { - { - Icon( - painter = textFieldType.trailingIcon()!!, - contentDescription = stringResource(id = R.string.textfield_trailing_icon), + CompositionLocalProvider(LocalTextSelectionColors provides colors.textSelectionColors) { + BasicTextField( + value = textFieldValueState, + modifier = Modifier + .heightIn( + min = textFieldType.minHeight(), + max = textFieldType.maxHeight(), ) - } - } else { - null - }, - leadingIcon = if (textFieldType.leadingIcon() != null) { - { - Icon( - painter = textFieldType.leadingIcon()!!, - contentDescription = stringResource(id = R.string.textfield_leading_icon), + .fillMaxWidth() + .focusRequester(focusRequester) + .onFocusChanged { focusState -> onFocusChanged(focusState) }, + onValueChange = { newTextFieldValue -> + textFieldValueState = newTextFieldValue + onValueChange(newTextFieldValue.text) + }, + enabled = textFieldType.isEnabled(), + readOnly = readOnly, + textStyle = StaticTypeScale.Default.body4.copy( + color = WeSpotThemeManager.colors.txtTitleColor, + ), + cursorBrush = SolidColor(cursorColor(isError).value), + visualTransformation = VisualTransformation.None, + keyboardOptions = keyBoardOption, + keyboardActions = keyboardActions, + interactionSource = interactionSource, + singleLine = singleLine, + decorationBox = @Composable { innerTextField -> + OutlinedTextFieldDefaults.DecorationBox( + value = textFieldValueState.text, + visualTransformation = VisualTransformation.None, + innerTextField = innerTextField, + placeholder = { + Text( + text = placeholder, + style = StaticTypeScale.Default.body4, + color = Gray400, + ) + }, + leadingIcon = if (textFieldType.leadingIcon() != null) { + { + Icon( + painter = textFieldType.leadingIcon()!!, + contentDescription = stringResource(id = R.string.textfield_leading_icon), + ) + } + } else { + null + }, + trailingIcon = if (textFieldType.trailingIcon() != null) { + { + Icon( + painter = textFieldType.trailingIcon()!!, + contentDescription = stringResource(id = R.string.textfield_trailing_icon), + ) + } + } else { + null + }, + singleLine = singleLine, + enabled = textFieldType.isEnabled(), + isError = isError, + interactionSource = interactionSource, + colors = colors, + container = { + OutlinedTextFieldDefaults.ContainerBox( + textFieldType.isEnabled(), + isError, + interactionSource, + colors, + WeSpotThemeManager.shapes.small, + focusedBorderThickness = 1.dp + ) + } ) } - } else { - null - }, - placeholder = { - Text( - text = placeholder, - style = StaticTypeScale.Default.body4, - color = Gray400, - ) - }, - colors = OutlinedTextFieldDefaults.colors( - focusedContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, - unfocusedContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, - focusedPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, - unfocusedPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, - focusedBorderColor = if (textFieldType == WsTextFieldType.Message) { - WeSpotThemeManager.colors.cardBackgroundColor - } else { - Primary400 - }, - unfocusedBorderColor = WeSpotThemeManager.colors.cardBackgroundColor, - disabledContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, - disabledPlaceholderColor = Gray400, - disabledBorderColor = WeSpotThemeManager.colors.cardBackgroundColor, - errorBorderColor = WeSpotThemeManager.colors.dangerColor, - errorContainerColor = WeSpotThemeManager.colors.cardBackgroundColor, - errorPlaceholderColor = WeSpotThemeManager.colors.disableBtnTxtColor, - ), - shape = WeSpotThemeManager.shapes.small, - textStyle = StaticTypeScale.Default.body4, - ) + ) + } } } +@Composable +private fun cursorColor(isError: Boolean): State { + val color = TextFieldDefaults.colors() + return rememberUpdatedState(if (isError) color.errorCursorColor else color.cursorColor) +} + + sealed interface WsTextFieldType { @Composable fun trailingIcon(): Painter?