99 */
1010package com.mifos.core.designsystem.component
1111
12+ import androidx.compose.animation.AnimatedContent
1213import androidx.compose.animation.AnimatedVisibility
1314import androidx.compose.foundation.interaction.MutableInteractionSource
1415import androidx.compose.foundation.interaction.collectIsFocusedAsState
16+ import androidx.compose.foundation.layout.fillMaxSize
1517import androidx.compose.foundation.layout.fillMaxWidth
1618import androidx.compose.foundation.layout.padding
1719import androidx.compose.foundation.text.KeyboardActions
1820import androidx.compose.foundation.text.KeyboardOptions
1921import androidx.compose.material.icons.Icons
20- import androidx.compose.material.icons.filled.CalendarToday
22+ import androidx.compose.material.icons.filled.CalendarMonth
2123import androidx.compose.material.icons.filled.Clear
2224import androidx.compose.material.icons.filled.Email
2325import androidx.compose.material.icons.filled.Person
@@ -35,13 +37,18 @@ import androidx.compose.runtime.Composable
3537import androidx.compose.runtime.getValue
3638import androidx.compose.runtime.mutableStateOf
3739import androidx.compose.runtime.remember
40+ import androidx.compose.runtime.rememberUpdatedState
3841import androidx.compose.runtime.setValue
3942import androidx.compose.ui.Modifier
43+ import androidx.compose.ui.draw.clip
4044import androidx.compose.ui.graphics.Shape
4145import androidx.compose.ui.graphics.vector.ImageVector
4246import androidx.compose.ui.platform.LocalDensity
4347import androidx.compose.ui.platform.testTag
48+ import androidx.compose.ui.semantics.contentDescription
49+ import androidx.compose.ui.semantics.semantics
4450import androidx.compose.ui.text.TextStyle
51+ import androidx.compose.ui.text.font.FontWeight
4552import androidx.compose.ui.text.input.ImeAction
4653import androidx.compose.ui.text.input.KeyboardCapitalization
4754import androidx.compose.ui.text.input.KeyboardType
@@ -51,6 +58,8 @@ import androidx.compose.ui.text.input.VisualTransformation
5158import androidx.compose.ui.text.style.TextOverflow
5259import androidx.compose.ui.unit.dp
5360import androidx.compose.ui.unit.sp
61+ import com.mifos.core.designsystem.icon.MifosIcons
62+ import com.mifos.core.designsystem.theme.DesignToken
5463import com.mifos.core.designsystem.theme.MifosTheme
5564import com.mifos.core.designsystem.theme.MifosTypography
5665import org.jetbrains.compose.ui.tooling.preview.Preview
@@ -240,7 +249,7 @@ fun MifosOutlinedTextField(
240249 onValueChange : (String ) -> Unit ,
241250 label : String ,
242251 error : String? ,
243- modifier : Modifier = Modifier .fillMaxWidth().padding(start = 16.dp, end = 16.dp ),
252+ modifier : Modifier = Modifier .fillMaxWidth().clip( DesignToken .shapes.medium ),
244253 maxLines : Int = 1,
245254 readOnly : Boolean = false,
246255 singleLine : Boolean = true,
@@ -251,6 +260,10 @@ fun MifosOutlinedTextField(
251260 enabled : Boolean = true,
252261) {
253262 OutlinedTextField (
263+ colors = OutlinedTextFieldDefaults .colors(
264+ focusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
265+ unfocusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
266+ ),
254267 value = value,
255268 onValueChange = onValueChange,
256269 label = { Text (label) },
@@ -267,10 +280,17 @@ fun MifosOutlinedTextField(
267280 } else {
268281 null
269282 },
283+ shape = DesignToken .shapes.medium,
270284 trailingIcon = trailingIcon,
271285 maxLines = maxLines,
272286 singleLine = singleLine,
273- textStyle = MaterialTheme .typography.bodyLarge,
287+ textStyle = TextStyle (
288+ color = MaterialTheme .colorScheme.onSurfaceVariant,
289+ fontSize = MaterialTheme .typography.bodyLarge.fontSize,
290+ lineHeight = 24 .sp,
291+ letterSpacing = 0.5f .sp,
292+ fontWeight = FontWeight .Normal ,
293+ ),
274294 keyboardOptions = KeyboardOptions (imeAction = ImeAction .Next , keyboardType = keyboardType),
275295 visualTransformation = visualTransformation,
276296 isError = error != null ,
@@ -285,10 +305,6 @@ fun MifosOutlinedTextField(
285305 } else {
286306 null
287307 },
288- colors = OutlinedTextFieldDefaults .colors(
289- focusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
290- unfocusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
291- ),
292308 )
293309}
294310
@@ -324,15 +340,18 @@ private fun PasswordToggleIcon(
324340private fun ClearIconButton (
325341 showClearIcon : Boolean ,
326342 clearIcon : ImageVector ,
327- modifier : Modifier = Modifier ,
328343 onClickClearIcon : () -> Unit ,
344+ modifier : Modifier = Modifier ,
329345) {
330346 AnimatedVisibility (
331347 visible = showClearIcon,
348+ modifier = modifier,
332349 ) {
333350 IconButton (
334351 onClick = onClickClearIcon,
335- modifier = modifier,
352+ modifier = Modifier .semantics {
353+ contentDescription = " clearIcon"
354+ },
336355 ) {
337356 Icon (
338357 imageVector = clearIcon,
@@ -344,34 +363,129 @@ private fun ClearIconButton(
344363
345364@Composable
346365fun MifosDatePickerTextField (
366+ enabled : Boolean = true,
347367 value : String ,
348- modifier : Modifier = Modifier .fillMaxWidth().padding(start = 16.dp, end = 16.dp),
368+ modifier : Modifier = Modifier
369+ .fillMaxSize()
370+ .clip(DesignToken .shapes.medium),
349371 label : String? = null,
350372 openDatePicker : () -> Unit ,
351373) {
352374 OutlinedTextField (
375+ enabled = enabled,
376+ colors = OutlinedTextFieldDefaults .colors(
377+ focusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
378+ unfocusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
379+ ),
353380 value = value,
354381 onValueChange = { },
355382 label = { Text (text = label?.let { label } ? : " " ) },
356383 readOnly = true ,
357384 modifier = modifier,
385+ shape = DesignToken .shapes.medium,
358386 maxLines = 1 ,
359387 textStyle = LocalDensity .current.run {
360- TextStyle (fontSize = 18 .sp)
388+ TextStyle (
389+ color = MaterialTheme .colorScheme.onSurfaceVariant,
390+ fontSize = MaterialTheme .typography.bodyLarge.fontSize,
391+ lineHeight = 24 .sp,
392+ letterSpacing = 0.5f .sp,
393+ fontWeight = FontWeight .Normal ,
394+ )
361395 },
362396 keyboardOptions = KeyboardOptions (imeAction = ImeAction .Next ),
363397 trailingIcon = {
364398 IconButton (onClick = { openDatePicker() }) {
365- Icon (imageVector = Icons .Default .CalendarToday , null )
399+ Icon (imageVector = Icons .Default .CalendarMonth , null )
366400 }
367401 },
368- colors = OutlinedTextFieldDefaults .colors(
369- focusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
370- unfocusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
371- ),
372402 )
373403}
374404
405+ @Composable
406+ fun MifosOutlinedTextField (
407+ value : String ,
408+ onValueChange : (String ) -> Unit ,
409+ label : String ,
410+ modifier : Modifier = Modifier ,
411+ shape : Shape = OutlinedTextFieldDefaults .shape,
412+ colors : TextFieldColors = OutlinedTextFieldDefaults .colors(
413+ focusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
414+ unfocusedBorderColor = MaterialTheme .colorScheme.secondaryContainer,
415+ errorBorderColor = MaterialTheme .colorScheme.error,
416+ ),
417+ textStyle : TextStyle = LocalTextStyle .current,
418+ interactionSource : MutableInteractionSource = remember { MutableInteractionSource () },
419+ config : MifosTextFieldConfig = MifosTextFieldConfig (),
420+ onClickClearIcon : () -> Unit = { onValueChange("") },
421+ ) {
422+ val isFocused by interactionSource.collectIsFocusedAsState()
423+ val showIcon by rememberUpdatedState(value.isNotEmpty())
424+
425+ OutlinedTextField (
426+ shape = shape,
427+ colors = colors,
428+ value = value,
429+ label = { Text (text = label) },
430+ onValueChange = onValueChange,
431+ textStyle = textStyle,
432+ modifier = modifier.fillMaxWidth(),
433+ enabled = config.enabled,
434+ readOnly = config.readOnly,
435+ visualTransformation = config.visualTransformation,
436+ keyboardOptions = config.keyboardOptions,
437+ keyboardActions = config.keyboardActions,
438+ interactionSource = interactionSource,
439+ singleLine = config.singleLine,
440+ maxLines = config.maxLines,
441+ minLines = config.minLines,
442+ leadingIcon = config.leadingIcon,
443+ isError = config.isError,
444+ trailingIcon = @Composable {
445+ AnimatedContent (
446+ targetState = config.showClearIcon && isFocused && showIcon,
447+ ) {
448+ if (it) {
449+ ClearIconButton (
450+ showClearIcon = true ,
451+ clearIcon = config.clearIcon,
452+ onClickClearIcon = onClickClearIcon,
453+ )
454+ } else {
455+ config.trailingIcon?.invoke()
456+ }
457+ }
458+ },
459+ supportingText = config.errorText?.let {
460+ {
461+ Text (
462+ modifier = Modifier .testTag(" errorTag" ),
463+ text = it,
464+ style = MifosTypography .bodySmall,
465+ color = MaterialTheme .colorScheme.error,
466+ )
467+ }
468+ },
469+ )
470+ }
471+
472+ data class MifosTextFieldConfig (
473+ val enabled : Boolean = true ,
474+ val showClearIcon : Boolean = true ,
475+ val readOnly : Boolean = false ,
476+ val clearIcon : ImageVector = MifosIcons .Close ,
477+ val isError : Boolean = false ,
478+ val errorText : String? = null ,
479+ val visualTransformation : VisualTransformation = VisualTransformation .None ,
480+ val keyboardActions : KeyboardActions = KeyboardActions .Default ,
481+ val singleLine : Boolean = true ,
482+ val maxLines : Int = if (singleLine) 1 else Int .MAX_VALUE ,
483+ val minLines : Int = 1 ,
484+ val keyboardOptions : KeyboardOptions = KeyboardOptions (imeAction = ImeAction .Next ),
485+ val trailingIcon : @Composable (() -> Unit )? = null ,
486+ val leadingIcon : @Composable (() -> Unit )? = null ,
487+ )
488+
375489@Preview
376490@Composable
377491private fun MifosOutlinedTextField_ValuePreview () {
0 commit comments