65 lines
2.4 KiB
Swift
65 lines
2.4 KiB
Swift
import SwiftUI
|
|
import Bedrock
|
|
|
|
struct LabeledFieldRow: View {
|
|
@Binding var entry: LabeledEntry
|
|
let valuePlaceholder: String
|
|
let labelSuggestions: [String]
|
|
var keyboardType: UIKeyboardType = .default
|
|
var autocapitalization: TextInputAutocapitalization = .sentences
|
|
var formatValue: ((String) -> String)?
|
|
var isValueValid: ((String) -> Bool)?
|
|
var validationMessage: String?
|
|
|
|
private var trimmedValue: String {
|
|
entry.value.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
}
|
|
|
|
private var showsValidationError: Bool {
|
|
guard let isValueValid else { return false }
|
|
guard !trimmedValue.isEmpty else { return false }
|
|
return !isValueValid(trimmedValue)
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: Design.Spacing.xSmall) {
|
|
HStack(spacing: Design.Spacing.medium) {
|
|
Menu {
|
|
ForEach(labelSuggestions, id: \.self) { suggestion in
|
|
Button(suggestion) {
|
|
entry.label = suggestion
|
|
}
|
|
}
|
|
} label: {
|
|
HStack(spacing: Design.Spacing.xSmall) {
|
|
Text(entry.label)
|
|
.foregroundStyle(Color.accentColor)
|
|
Image(systemName: "chevron.up.chevron.down")
|
|
.typography(.caption2)
|
|
.foregroundStyle(Color.secondary)
|
|
}
|
|
}
|
|
.frame(width: 80, alignment: .leading)
|
|
|
|
TextField(valuePlaceholder, text: $entry.value)
|
|
.keyboardType(keyboardType)
|
|
.textInputAutocapitalization(autocapitalization)
|
|
.onChange(of: entry.value) { _, newValue in
|
|
guard let formatValue else { return }
|
|
let formatted = formatValue(newValue)
|
|
if formatted != newValue {
|
|
entry.value = formatted
|
|
}
|
|
}
|
|
}
|
|
|
|
if showsValidationError, let validationMessage {
|
|
Text(validationMessage)
|
|
.typography(.caption)
|
|
.foregroundStyle(Color.Accent.red)
|
|
.padding(.leading, 80 + Design.Spacing.medium)
|
|
}
|
|
}
|
|
}
|
|
}
|