BusinessCard/BusinessCard/Views/Features/Contacts/Sheets/LabeledFieldRow.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)
}
}
}
}