Skip to content

Commit cec0416

Browse files
marekpelc-pegalukaszgajewski-pega
authored andcommitted
TASK-1861767: simple support for RichText
- render RichText as read-only
1 parent 28bbd0f commit cec0416

File tree

12 files changed

+147
-4
lines changed

12 files changed

+147
-4
lines changed

core/src/commonMain/kotlin/com/pega/constellation/sdk/kmp/core/components/ComponentRegistry.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.OneColumn
2323
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.Phone
2424
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RadioButtons
2525
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.Region
26+
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RichText
2627
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RootContainer
2728
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.SimpleTable
2829
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.SimpleTableManual
@@ -61,6 +62,7 @@ import com.pega.constellation.sdk.kmp.core.components.fields.EmailComponent
6162
import com.pega.constellation.sdk.kmp.core.components.fields.IntegerComponent
6263
import com.pega.constellation.sdk.kmp.core.components.fields.PhoneComponent
6364
import com.pega.constellation.sdk.kmp.core.components.fields.RadioButtonsComponent
65+
import com.pega.constellation.sdk.kmp.core.components.fields.RichTextComponent
6466
import com.pega.constellation.sdk.kmp.core.components.fields.TextAreaComponent
6567
import com.pega.constellation.sdk.kmp.core.components.fields.TextInputComponent
6668
import com.pega.constellation.sdk.kmp.core.components.fields.TimeComponent
@@ -106,6 +108,7 @@ object ComponentRegistry {
106108
Def(SimpleTableManual) { SimpleTableManualComponent(it) },
107109
Def(SimpleTableSelect) { SimpleTableSelectComponent(it) },
108110
Def(TextArea) { TextAreaComponent(it) },
111+
Def(RichText) { RichTextComponent(it) },
109112
Def(TextInput) { TextInputComponent(it) },
110113
Def(Time) { TimeComponent(it) },
111114
Def(URL) { UrlComponent(it) },

core/src/commonMain/kotlin/com/pega/constellation/sdk/kmp/core/components/ComponentTypes.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ object ComponentTypes {
3838
val Integer = ComponentType("Integer")
3939
val Phone = ComponentType("Phone")
4040
val RadioButtons = ComponentType("RadioButtons")
41+
val RichText = ComponentType("RichText")
4142
val TextArea = ComponentType("TextArea")
4243
val TextInput = ComponentType("TextInput")
4344
val Time = ComponentType("Time")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.pega.constellation.sdk.kmp.core.components.fields
2+
3+
import com.pega.constellation.sdk.kmp.core.api.ComponentContext
4+
5+
class RichTextComponent(context: ComponentContext) : FieldComponent(context)

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ androidx-test-junit = "1.3.0"
1313
compose-hot-reload = "1.0.0"
1414
compose-multiplatform = "1.9.0" # warning: update bumps kotlinx-datetime, which breaks iOS
1515
compose-navigation = "2.9.1"
16+
htmlconverter = "1.1.0"
1617
kotlin = "2.2.21"
1718
kotlinx-coroutines = "1.10.2"
1819
kotlinx-datetime = "0.6.2" # warning: update breaks iOS compilation
@@ -43,6 +44,7 @@ androidx-ui-test-junit4-android = { group = "androidx.compose.ui", name = "ui-te
4344
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
4445
androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
4546
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
47+
htmlconverter = { module = "be.digitalia.compose.htmlconverter:htmlconverter", version.ref = "htmlconverter" }
4648
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
4749
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
4850
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { FieldBaseComponent } from "./field-base.component.js";
2+
3+
export class RichTextComponent extends FieldBaseComponent {}

scripts/dxcomponents/mappings/sdk-pega-component-map.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import { TimeComponent } from "../components/fields/time.component.js";
4242
import { UrlComponent } from "../components/fields/url.component.js";
4343
// import { UserReferenceComponent } from './_components/field/user-reference/user-reference.component';
4444
// import { ScalarListComponent } from './_components/field/scalar-list/scalar-list.component';
45-
// import { RichTextComponent } from './_components/field/rich-text/rich-text.component';
45+
import { RichTextComponent } from "../components/fields/rich-text.component.js";
4646
import { UnsupportedComponent } from "../components/widgets/unsupported.component.js";
4747

4848
// Template components
@@ -207,7 +207,7 @@ const pegaSdkComponentMap = {
207207
reference: ReferenceComponent,
208208
RadioButtons: RadioButtonsComponent,
209209
Region: RegionComponent,
210-
// RichText: RichTextComponent,
210+
RichText: RichTextComponent,
211211
// RichTextEditor: RichTextEditorComponent,
212212
RootContainer: RootContainerComponent,
213213
// ScalarList: ScalarListComponent,

ui-components-cmp/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ kotlin {
4040
implementation(libs.kotlinx.serialization.json)
4141
implementation(libs.table.m3)
4242
implementation(libs.compose.dnd)
43+
implementation(libs.htmlconverter)
4344
}
4445
}
4546

ui-components-cmp/src/commonMain/kotlin/com/pega/constellation/sdk/kmp/ui/components/cmp/controls/form/FieldValue.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,21 @@ import androidx.compose.material3.Text
66
import androidx.compose.runtime.Composable
77
import androidx.compose.ui.Modifier
88
import androidx.compose.ui.graphics.Color
9+
import androidx.compose.ui.text.AnnotatedString
910
import androidx.compose.ui.unit.sp
1011

1112
@Composable
1213
fun FieldValue(label: String, value: String) {
14+
FieldValue(label, AnnotatedString(value))
15+
}
16+
17+
@Composable
18+
fun FieldValue(label: String, value: AnnotatedString) {
1319
Column(modifier = Modifier.fillMaxWidth()) {
1420
if (label.trim().isNotEmpty()) {
1521
Text(label, fontSize = 14.sp, color = Color.Gray)
1622
}
17-
Text(value.ifEmpty { "---" }, fontSize = 14.sp)
23+
val annotated = if (value.trim().isNotEmpty()) value else AnnotatedString("---")
24+
Text(annotated, fontSize = 14.sp)
1825
}
1926
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.pega.constellation.sdk.kmp.ui.components.cmp.controls.form
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.remember
5+
import androidx.compose.ui.Modifier
6+
import androidx.compose.ui.text.input.TextFieldValue
7+
import be.digitalia.compose.htmlconverter.htmlToAnnotatedString
8+
import com.pega.constellation.sdk.kmp.ui.components.cmp.controls.form.internal.Input
9+
10+
@Composable
11+
fun RichText(
12+
value: String,
13+
label: String,
14+
modifier: Modifier = Modifier,
15+
helperText: String = "",
16+
validateMessage: String = "",
17+
required: Boolean = false,
18+
disabled: Boolean = false,
19+
readOnly: Boolean = false
20+
) {
21+
if (readOnly) {
22+
// Read-only RichText renders on web as display-only
23+
RichTextFieldValue(label, value)
24+
} else {
25+
Input(
26+
value = TextFieldValue(rememberAnnotated(value)),
27+
label = label,
28+
modifier = modifier,
29+
helperText = helperText,
30+
validateMessage = validateMessage,
31+
required = required,
32+
disabled = disabled,
33+
readOnly = true, // not allowing editing in RichText for now
34+
lines = 3
35+
)
36+
}
37+
}
38+
39+
@Composable
40+
fun RichTextFieldValue(label: String, value: String) {
41+
FieldValue(label, rememberAnnotated(value))
42+
}
43+
44+
@Composable
45+
private fun rememberAnnotated(value: String) =
46+
remember(value) { htmlToAnnotatedString(value, compactMode = true) }

ui-components-cmp/src/commonMain/kotlin/com/pega/constellation/sdk/kmp/ui/components/cmp/controls/form/internal/Input.kt

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
1010
import androidx.compose.runtime.remember
1111
import androidx.compose.ui.Modifier
1212
import androidx.compose.ui.focus.onFocusChanged
13+
import androidx.compose.ui.text.input.TextFieldValue
1314
import com.pega.constellation.sdk.kmp.ui.components.cmp.controls.form.Label
1415

1516
@Composable
@@ -31,11 +32,52 @@ internal fun Input(
3132
leadingIcon: @Composable (() -> Unit)? = null,
3233
trailingIcon: @Composable (() -> Unit)? = null,
3334
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
35+
) {
36+
Input(
37+
value = TextFieldValue(value),
38+
label = label,
39+
modifier = modifier,
40+
helperText = helperText,
41+
validateMessage = validateMessage,
42+
hideLabel = hideLabel,
43+
placeholder = placeholder,
44+
required = required,
45+
disabled = disabled,
46+
readOnly = readOnly,
47+
onValueChange = onValueChange,
48+
onFocusChange = onFocusChange,
49+
lines = lines,
50+
keyboardOptions = keyboardOptions,
51+
leadingIcon = leadingIcon,
52+
trailingIcon = trailingIcon,
53+
interactionSource = interactionSource
54+
)
55+
}
56+
57+
@Composable
58+
internal fun Input(
59+
value: TextFieldValue,
60+
label: String,
61+
modifier: Modifier = Modifier,
62+
helperText: String = "",
63+
validateMessage: String = "",
64+
hideLabel: Boolean = false,
65+
placeholder: String = "",
66+
required: Boolean = false,
67+
disabled: Boolean = false,
68+
readOnly: Boolean = false,
69+
onValueChange: (String) -> Unit = {},
70+
onFocusChange: (Boolean) -> Unit = {},
71+
lines: Int = 1,
72+
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
73+
leadingIcon: @Composable (() -> Unit)? = null,
74+
trailingIcon: @Composable (() -> Unit)? = null,
75+
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
3476
) {
3577
Column(modifier = modifier) {
3678
OutlinedTextField(
3779
value = value,
38-
onValueChange = onValueChange,
80+
onValueChange = { onValueChange(it.text) },
3981
modifier = Modifier
4082
.fillMaxWidth()
4183
.onFocusChanged { onFocusChange(it.isFocused) },

0 commit comments

Comments
 (0)