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

HMA-8827-password-input-view #191

Merged
merged 15 commits into from
Oct 25, 2024
5 changes: 5 additions & 0 deletions components-compose/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ Allowed headings:

## [Unreleased]

### Added

* `PasswordInputView` component added with show/hide feature
emmaatkins marked this conversation as resolved.
Show resolved Hide resolved
* `requiresSequenceSpacing` parameter added to `TextInputView` to enable additional character spacing for use during sequences

## [0.1.5] - 2024-10-25Z

### Changed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.gov.hmrc.components.compose.molecule.input

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import uk.gov.hmrc.components.compose.atom.text.BodyText
import uk.gov.hmrc.components.compose.atom.text.BoldText
import uk.gov.hmrc.components.compose.atom.text.ErrorText
import uk.gov.hmrc.components.compose.molecule.input.CommonInputView.CHAR_COUNT_WIDTH
import uk.gov.hmrc.components.compose.molecule.input.CommonInputView.ERROR_TEXT_WITH_CHAR_COUNT_WIDTH
import uk.gov.hmrc.components.compose.ui.theme.HmrcTheme
import uk.gov.hmrc.components.compose.ui.theme.HmrcTheme.typography

@Suppress("LongParameterList")
@Composable
internal fun TextField(
modifier: Modifier,
isError: Boolean,
value: String,
onInputValueChange: (String) -> Unit,
prefix: @Composable() (() -> Unit)?,
placeholderText: @Composable (() -> Unit)?,
supportingText: @Composable() (() -> Unit)?,
singleLine: Boolean,
keyboardOptions: KeyboardOptions,
visualTransformation: VisualTransformation,
colors: TextFieldColors,
trailingIcon: @Composable() (() -> Unit)? = null,
textStyle: TextStyle = typography.body,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
OutlinedTextField(
modifier = modifier.fillMaxWidth(),
isError = isError,
value = value,
onValueChange = onInputValueChange,
prefix = prefix,
placeholder = placeholderText,
supportingText = supportingText,
trailingIcon = trailingIcon,
singleLine = singleLine,
keyboardOptions = keyboardOptions,
textStyle = textStyle,
colors = colors,
shape = RoundedCornerShape(0),
visualTransformation = visualTransformation,
interactionSource = interactionSource,
)
}

@Composable
internal fun Label(labelText: String?, labelContentDescription: String?,) {
labelText?.let { label ->
BoldText(
text = label,
modifier = Modifier
.semantics { labelContentDescription?.let { contentDescription = it } }
.padding(bottom = HmrcTheme.dimensions.hmrcSpacing8)
)
}
}

@Composable
internal fun Hint(hintText: String?, hintContentDescription: String?) {
hintText?.let { hint ->
BodyText(
text = hint,
modifier = Modifier
.semantics { hintContentDescription?.let { contentDescription = it } }
.padding(bottom = HmrcTheme.dimensions.hmrcSpacing8)
)
}
}

internal fun error(errorText: String?, errorContentDescription: String?):
@Composable (() -> Unit)? = errorText?.let {
@Composable {
ErrorText(
text = it,
modifier = Modifier.semantics {
errorContentDescription?.let {
contentDescription = it
}
}
)
}
}

internal fun errorTextCounterCombo(
errorText: String?,
errorContentDescription: String?,
characterCount: Int?,
localValue: String
):
@Composable (() -> Unit) = @Composable {
Row {
Column(
horizontalAlignment = Alignment.Start,
modifier = Modifier.fillMaxWidth(ERROR_TEXT_WITH_CHAR_COUNT_WIDTH)
) {
if (errorText != null) {
ErrorText(
text = errorText,
modifier = Modifier.semantics {
errorContentDescription?.let {
contentDescription = it
}
}
)
}
}
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier.fillMaxWidth(CHAR_COUNT_WIDTH)
) {
val textStyle = characterCount?.let { limit ->
if (localValue.length > limit) typography.errorText else typography.body
} ?: typography.body
Text(
text = "${localValue.length}/$characterCount",
style = textStyle,
textAlign = TextAlign.End,
)
}
}
}

object CommonInputView {
const val ERROR_TEXT_WITH_CHAR_COUNT_WIDTH = 0.8f
const val CHAR_COUNT_WIDTH = 0.95f
}

@Composable
fun Modifier.adjustPaddingForCounter(counterEnabled: Boolean, localError: String?) = this.padding(
bottom = if (counterEnabled || !localError.isNullOrEmpty()) 0.dp else HmrcTheme.dimensions.hmrcIconSize24
)
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ fun CurrencyInputView(
errorContentDescription: String? = null,
singleLine: Boolean = true,
enableDecimal: Boolean = true,
maxChars: Int? = null,
maxChars: Int? = null
) {

// pattern matches a decimal number
val decimalPattern = remember { Regex("^([0-9]*)(\\.?)([0-9]*)$") }
// pattern matches a non decimal number
Expand Down Expand Up @@ -71,11 +70,11 @@ fun CurrencyInputView(
placeholderText = placeholderText,
errorText = errorText,
errorContentDescription = errorContentDescription,
maxChars = maxChars,
singleLine = singleLine,
keyboardOptions = KeyboardOptions(
keyboardType = if (enableDecimal) KeyboardType.Decimal else KeyboardType.Number
),
maxChars = maxChars
)
)
}

Expand All @@ -87,7 +86,7 @@ fun CurrencyInputViewPreview() {
onInputValueChange = { },
labelText = "Label",
hintText = "Hint",
placeholderText = "Text"
placeholderText = "Text",
)
}
}
Loading