feat(design-system): add MsEnumDropdown component and update roadmap
- Introduced a reusable `MsEnumDropdown` component for selecting enum values with customizable options, labels, and error handling. - Updated `Frontend_Komponenten_Roadmap.md` to reflect progress in Phase 3, marking `MsEnumDropdown` as completed. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -39,11 +39,11 @@ Turniermanagement bedeutet Arbeit mit Listen. Wir benötigen mächtige, aber kom
|
|||||||
* [x] Filter-Chips für schnelle Status-Wechsel.
|
* [x] Filter-Chips für schnelle Status-Wechsel.
|
||||||
* [x] Anzeige der Trefferanzahl (Result Count).
|
* [x] Anzeige der Trefferanzahl (Result Count).
|
||||||
|
|
||||||
## Phase 3: Formular- & Eingabe-System (Die Datenerfassung) ⚪ [ZUKUNFT]
|
## Phase 3: Formular- & Eingabe-System (Die Datenerfassung) 🔵 [IN ARBEIT]
|
||||||
|
|
||||||
Eingabe von Stammdaten muss schnell und fehlerfrei erfolgen.
|
Eingabe von Stammdaten muss schnell und fehlerfrei erfolgen.
|
||||||
|
|
||||||
* [ ] **`MsEnumDropdown`:** Automatisches Mapping von Backend-Enums (ÖTO) auf UI-Auswahl.
|
* [x] **`MsEnumDropdown`:** Automatisches Mapping von Backend-Enums (ÖTO) auf UI-Auswahl.
|
||||||
* [ ] **`MsValidationWrapper`:** Konsistente Anzeige von Fehlern (z.B. "Lizenz für diese Klasse nicht ausreichend").
|
* [ ] **`MsValidationWrapper`:** Konsistente Anzeige von Fehlern (z.B. "Lizenz für diese Klasse nicht ausreichend").
|
||||||
* [ ] **`MsSearchableSelect`:** Für die Verknüpfung von Reitern/Pferden (Autocomplete).
|
* [ ] **`MsSearchableSelect`:** Für die Verknüpfung von Reitern/Pferden (Autocomplete).
|
||||||
|
|
||||||
|
|||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
package at.mocode.frontend.core.designsystem.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein generisches Dropdown zur Auswahl von Enum-Werten.
|
||||||
|
*
|
||||||
|
* @param label Das Label über dem Dropdown.
|
||||||
|
* @param options Alle verfügbaren Enum-Optionen (z.B. SparteE.values()).
|
||||||
|
* @param selectedOption Der aktuell gewählte Wert.
|
||||||
|
* @param onOptionSelected Callback bei Auswahl einer Option.
|
||||||
|
* @param optionLabel Transformation des Enums in einen lesbaren Text (Standard: toString()).
|
||||||
|
* @param modifier Modifier für die gesamte Komponente.
|
||||||
|
* @param enabled Ob das Dropdown bearbeitbar ist.
|
||||||
|
* @param isError Ob ein Fehler vorliegt.
|
||||||
|
* @param errorMessage Die anzuzeigende Fehlermeldung.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun <T : Enum<T>> MsEnumDropdown(
|
||||||
|
label: String,
|
||||||
|
options: Array<T>,
|
||||||
|
selectedOption: T?,
|
||||||
|
onOptionSelected: (T) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
optionLabel: (T) -> String = { it.name },
|
||||||
|
enabled: Boolean = true,
|
||||||
|
isError: Boolean = false,
|
||||||
|
errorMessage: String? = null
|
||||||
|
) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = expanded,
|
||||||
|
onExpandedChange = { if (enabled) expanded = it }
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedOption?.let { optionLabel(it) } ?: "",
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(label, style = MaterialTheme.typography.bodySmall) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||||
|
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
|
||||||
|
modifier = Modifier
|
||||||
|
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryEditable, enabled)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
isError = isError,
|
||||||
|
enabled = enabled,
|
||||||
|
singleLine = true,
|
||||||
|
textStyle = MaterialTheme.typography.bodyMedium,
|
||||||
|
shape = MaterialTheme.shapes.small
|
||||||
|
)
|
||||||
|
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
options.forEach { option ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = optionLabel(option),
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onOptionSelected(option)
|
||||||
|
expanded = false
|
||||||
|
},
|
||||||
|
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError && errorMessage != null) {
|
||||||
|
Text(
|
||||||
|
text = errorMessage,
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
modifier = Modifier.padding(start = 16.dp, top = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user