Skip to content

Commit

Permalink
[minor] adds multi-select checkbox controls
Browse files Browse the repository at this point in the history
  • Loading branch information
cjbrooks12 committed Jul 16, 2022
1 parent e8bfe23 commit 60e880f
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Adds code editor control
- Connects rich text widget to form state
- adds multi-select checkbox controls

## 0.2.0 - 2022-07-05

Expand Down
33 changes: 33 additions & 0 deletions example/src/jvmMain/resources/kitchenSink/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,39 @@
"title": "FooBar"
}
]
},

"checkboxesEnum": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string",
"enum": [
"foo",
"bar",
"foobar"
]
}
},
"checkboxesOneOf": {
"type": "array",
"uniqueItems": true,
"items": {
"oneOf": [
{
"const": "foo",
"title": "Foo"
},
{
"const": "bar",
"title": "Bar"
},
{
"const": "foobar",
"title": "FooBar"
}
]
}
}
}
},
Expand Down
8 changes: 8 additions & 0 deletions example/src/jvmMain/resources/kitchenSink/uiSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@
"type": "Category",
"label": "Multi-Select",
"elements": [
{
"type": "Control",
"scope": "#/properties/strings/properties/checkboxesEnum"
},
{
"type": "Control",
"scope": "#/properties/strings/properties/checkboxesOneOf"
}
]
},
{
Expand Down
10 changes: 10 additions & 0 deletions json-forms-compose/api/android/json-forms-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public final class com/copperleaf/forms/compose/controls/ComposableSingletons$De
public static field lambda-15 Lkotlin/jvm/functions/Function3;
public static field lambda-16 Lkotlin/jvm/functions/Function3;
public static field lambda-17 Lkotlin/jvm/functions/Function3;
public static field lambda-18 Lkotlin/jvm/functions/Function3;
public static field lambda-19 Lkotlin/jvm/functions/Function3;
public static field lambda-2 Lkotlin/jvm/functions/Function3;
public static field lambda-3 Lkotlin/jvm/functions/Function3;
public static field lambda-4 Lkotlin/jvm/functions/Function3;
Expand All @@ -34,6 +36,8 @@ public final class com/copperleaf/forms/compose/controls/ComposableSingletons$De
public final fun getLambda-15$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-16$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-17$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-18$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-19$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-2$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-3$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-4$json_forms_compose_release ()Lkotlin/jvm/functions/Function3;
Expand Down Expand Up @@ -84,6 +88,8 @@ public final class com/copperleaf/forms/compose/controls/ControlScope {

public final class com/copperleaf/forms/compose/controls/DefaultControlsKt {
public static final fun checkbox (Lcom/copperleaf/forms/core/BooleanControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun checkboxesEnum (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun checkboxesOneOf (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun codeEditor (Lcom/copperleaf/forms/core/StringControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun control (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun control (Lcom/copperleaf/forms/core/IntegerControl;)Lcom/copperleaf/forms/compose/form/Registered;
Expand All @@ -103,10 +109,14 @@ public final class com/copperleaf/forms/compose/controls/LayoutKt {
}

public final class com/copperleaf/forms/compose/controls/TestersKt {
public static final fun hasArrayItemProperty (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun hasArrayItemType (Lcom/copperleaf/forms/core/ui/UiElement$Control;Lcom/copperleaf/forms/core/StringControl;)Z
public static final fun hasSchemaProperty (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun matchesControlType (Lcom/copperleaf/forms/core/ui/UiElement$Control;Lcom/copperleaf/forms/core/ControlType;)Z
public static final fun optionFieldIs (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;Ljava/lang/String;)Z
public static final fun optionIsEnabled (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun schemaPropertyIs (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;Ljava/lang/String;)Z
public static final fun schemaPropertyIsEnabled (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
}

public final class com/copperleaf/forms/compose/elements/ComposableSingletons$DefaultUiElementsKt {
Expand Down
10 changes: 10 additions & 0 deletions json-forms-compose/api/jvm/json-forms-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public final class com/copperleaf/forms/compose/controls/ComposableSingletons$De
public static field lambda-15 Lkotlin/jvm/functions/Function3;
public static field lambda-16 Lkotlin/jvm/functions/Function3;
public static field lambda-17 Lkotlin/jvm/functions/Function3;
public static field lambda-18 Lkotlin/jvm/functions/Function3;
public static field lambda-19 Lkotlin/jvm/functions/Function3;
public static field lambda-2 Lkotlin/jvm/functions/Function3;
public static field lambda-3 Lkotlin/jvm/functions/Function3;
public static field lambda-4 Lkotlin/jvm/functions/Function3;
Expand All @@ -27,6 +29,8 @@ public final class com/copperleaf/forms/compose/controls/ComposableSingletons$De
public final fun getLambda-15$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-16$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-17$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-18$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-19$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-2$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-3$json_forms_compose ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-4$json_forms_compose ()Lkotlin/jvm/functions/Function3;
Expand Down Expand Up @@ -77,6 +81,8 @@ public final class com/copperleaf/forms/compose/controls/ControlScope {

public final class com/copperleaf/forms/compose/controls/DefaultControlsKt {
public static final fun checkbox (Lcom/copperleaf/forms/core/BooleanControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun checkboxesEnum (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun checkboxesOneOf (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun codeEditor (Lcom/copperleaf/forms/core/StringControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun control (Lcom/copperleaf/forms/core/ArrayControl;)Lcom/copperleaf/forms/compose/form/Registered;
public static final fun control (Lcom/copperleaf/forms/core/IntegerControl;)Lcom/copperleaf/forms/compose/form/Registered;
Expand All @@ -96,10 +102,14 @@ public final class com/copperleaf/forms/compose/controls/LayoutKt {
}

public final class com/copperleaf/forms/compose/controls/TestersKt {
public static final fun hasArrayItemProperty (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun hasArrayItemType (Lcom/copperleaf/forms/core/ui/UiElement$Control;Lcom/copperleaf/forms/core/StringControl;)Z
public static final fun hasSchemaProperty (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun matchesControlType (Lcom/copperleaf/forms/core/ui/UiElement$Control;Lcom/copperleaf/forms/core/ControlType;)Z
public static final fun optionFieldIs (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;Ljava/lang/String;)Z
public static final fun optionIsEnabled (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
public static final fun schemaPropertyIs (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;Ljava/lang/String;)Z
public static final fun schemaPropertyIsEnabled (Lcom/copperleaf/forms/core/ui/UiElement$Control;Ljava/lang/String;)Z
}

public final class com/copperleaf/forms/compose/elements/ComposableSingletons$DefaultUiElementsKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.copperleaf.forms.compose.form

import com.copperleaf.forms.compose.controls.ControlRenderer
import com.copperleaf.forms.compose.controls.checkbox
import com.copperleaf.forms.compose.controls.checkboxesEnum
import com.copperleaf.forms.compose.controls.checkboxesOneOf
import com.copperleaf.forms.compose.controls.codeEditor
import com.copperleaf.forms.compose.controls.control
import com.copperleaf.forms.compose.controls.dropdownEnum
Expand Down Expand Up @@ -31,21 +33,30 @@ import com.copperleaf.forms.core.ui.UiElement

public actual fun UiElement.Control.Companion.defaults(): List<Registered<UiElement.Control, ControlRenderer>> =
listOf(
// text fields
StringControl.control(),
StringControl.richText(),
StringControl.codeEditor(),

// single-select
StringControl.dropdownEnum(),
StringControl.dropdownOneOf(),
StringControl.radioButtonEnum(),
StringControl.radioButtonOneOf(),

// multi-select
ArrayControl.checkboxesEnum(),
ArrayControl.checkboxesOneOf(),

// number controls
IntegerControl.control(),
NumberControl.control(),

// boolean controls
BooleanControl.checkbox(),
BooleanControl.switch(),

// composite controls
ObjectControl.control(),
ArrayControl.control(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

// StringControls
// Text Field Controls
// ---------------------------------------------------------------------------------------------------------------------

public fun StringControl.control(): Registered<UiElement.Control, ControlRenderer> = uiControl {
Expand Down Expand Up @@ -204,6 +204,9 @@ public fun StringControl.codeEditor(): Registered<UiElement.Control, ControlRend
}
}

// Single-Select Controls
// ---------------------------------------------------------------------------------------------------------------------

public fun StringControl.dropdownEnum(): Registered<UiElement.Control, ControlRenderer> = uiControl(
rank = 20,
tester = { hasSchemaProperty("enum") }
Expand All @@ -220,7 +223,7 @@ public fun StringControl.dropdownEnum(): Registered<UiElement.Control, ControlRe
)

var dropdownIsVisible by remember { mutableStateOf(false) }
val allDropdownOptions: List<String> = remember {
val allOptions: List<String> = remember {
control.schemaConfig.arrayAt("enum").map { it.jsonPrimitive.content }
}

Expand Down Expand Up @@ -248,8 +251,8 @@ public fun StringControl.dropdownEnum(): Registered<UiElement.Control, ControlRe
expanded = dropdownIsVisible && isEnabled,
onDismissRequest = { dropdownIsVisible = false },
) {
if (allDropdownOptions.isNotEmpty()) {
allDropdownOptions.forEach { option ->
if (allOptions.isNotEmpty()) {
allOptions.forEach { option ->
DropdownMenuItem(
onClick = {
updateText(TextFieldValue(option))
Expand Down Expand Up @@ -283,7 +286,7 @@ public fun StringControl.dropdownOneOf(): Registered<UiElement.Control, ControlR
)

var dropdownIsVisible by remember { mutableStateOf(false) }
val allDropdownOptions: List<Pair<String, String>> = remember {
val allOptions: List<Pair<String, String>> = remember {
control.schemaConfig.arrayAt("oneOf").map {
it.jsonObject.string("const") to it.jsonObject.string("title")
}
Expand Down Expand Up @@ -314,8 +317,8 @@ public fun StringControl.dropdownOneOf(): Registered<UiElement.Control, ControlR
expanded = dropdownIsVisible && isEnabled,
onDismissRequest = { dropdownIsVisible = false },
) {
if (allDropdownOptions.isNotEmpty()) {
allDropdownOptions.forEach { (const, title) ->
if (allOptions.isNotEmpty()) {
allOptions.forEach { (const, title) ->
DropdownMenuItem(
onClick = {
updateText(TextFieldValue(const))
Expand All @@ -341,12 +344,12 @@ public fun StringControl.radioButtonEnum(): Registered<UiElement.Control, Contro
it.jsonPrimitive.content
}

val allDropdownOptions: List<String> = remember {
val allOptions: List<String> = remember {
control.schemaConfig.arrayAt("enum").map { it.jsonPrimitive.content }
}

Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(12.dp)) {
allDropdownOptions.forEach {
allOptions.forEach {
Row(Modifier.clickable { updateFormState(it) }) {
RadioButton(
selected = currentValue == it,
Expand All @@ -367,14 +370,14 @@ public fun StringControl.radioButtonOneOf(): Registered<UiElement.Control, Contr
it.jsonPrimitive.content
}

val allDropdownOptions: List<Pair<String, String>> = remember {
val allOptions: List<Pair<String, String>> = remember {
control.schemaConfig.arrayAt("oneOf").map {
it.jsonObject.string("const") to it.jsonObject.string("title")
}
}

Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(12.dp)) {
allDropdownOptions.forEach { (const, title) ->
allOptions.forEach { (const, title) ->
Row(Modifier.clickable { updateFormState(const) }) {
RadioButton(
selected = currentValue == const,
Expand All @@ -387,6 +390,93 @@ public fun StringControl.radioButtonOneOf(): Registered<UiElement.Control, Contr
}
}

// Multi-Select Controls
// ---------------------------------------------------------------------------------------------------------------------

public fun ArrayControl.checkboxesEnum(): Registered<UiElement.Control, ControlRenderer> = uiControl(
rank = 20,
tester = { hasSchemaProperty("uniqueItems") && hasArrayItemType(StringControl) && hasArrayItemProperty("enum") }
) {
val selectedValues: List<String> = getTypedValue(emptyList()) {
if (it == JsonNull) {
emptyList()
} else {
it.jsonArray.map { it.jsonPrimitive.content }
}
}
val allOptions: List<String> = remember {
control.schemaConfig.objectAt("items").arrayAt("enum").map { it.jsonPrimitive.content }
}

Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(12.dp)) {
allOptions.forEach { option ->
Row(Modifier.clickable {
if (option in selectedValues) {
sendFormAction(
pointer = dataPointer + "/${selectedValues.indexOf(option)}",
action = JsonPointerAction.RemoveValue,
)
} else {
sendFormAction(
pointer = dataPointer + "/${selectedValues.size}",
action = JsonPointerAction.SetValue(option),
)
}
markAsTouched()
}) {
Checkbox(
checked = option in selectedValues,
onCheckedChange = null,
modifier = Modifier.padding(end = 8.dp)
)
Text(option)
}
}
}
}

public fun ArrayControl.checkboxesOneOf(): Registered<UiElement.Control, ControlRenderer> = uiControl(
rank = 21,
tester = { hasSchemaProperty("uniqueItems") && hasArrayItemProperty("oneOf") }
) {
val selectedValues: List<String> = getTypedValue(emptyList()) {
if (it == JsonNull) {
emptyList()
} else {
it.jsonArray.map { it.jsonPrimitive.content }
}
}
val allOptions: List<Pair<String, String>> = remember {
control.schemaConfig.objectAt("items").arrayAt("oneOf").map { it.string("const") to it.string("title") }
}

Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(12.dp)) {
allOptions.forEach { (const, title) ->
Row(Modifier.clickable {
if (const in selectedValues) {
sendFormAction(
pointer = dataPointer + "/${selectedValues.indexOf(const)}",
action = JsonPointerAction.RemoveValue,
)
} else {
sendFormAction(
pointer = dataPointer + "/${selectedValues.size}",
action = JsonPointerAction.SetValue(const),
)
}
markAsTouched()
}) {
Checkbox(
checked = const in selectedValues,
onCheckedChange = null,
modifier = Modifier.padding(end = 8.dp)
)
Text(title)
}
}
}
}

// Number Controls
// ---------------------------------------------------------------------------------------------------------------------

Expand Down
Loading

0 comments on commit 60e880f

Please sign in to comment.