You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
4.1 KiB

import SwiftUI
// MARK: - General Text Input Component
struct TextInputView: View {
@Binding var content: String
@FocusState var isContentFieldFocused: Bool
let placeholder: String
let maxCharacters: Int
var body: some View {
VStack(spacing: 8) {
ZStack {
// Input field body
TextEditor(text: $content)
.frame(minHeight: 120)
.padding(8)
.background(Color(.systemBackground))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(isContentFieldFocused ? Color.blue : Color(.systemGray4), lineWidth: 1)
)
.focused($isContentFieldFocused)
.onChange(of: content) { newValue in
// Limit maximum characters
if newValue.count > maxCharacters {
content = String(newValue.prefix(maxCharacters))
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("done".localized) {
isContentFieldFocused = false
}
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
// Placeholder text - top-left aligned
if content.isEmpty && !isContentFieldFocused {
VStack {
HStack {
Text(placeholder)
.foregroundColor(.secondary)
.font(.body)
Spacer()
}
Spacer()
}
.padding(16)
.allowsHitTesting(false)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
// Character count and limit hints - below input field
HStack {
Spacer() // Pushes content to the right
VStack(alignment: .trailing, spacing: 4) {
// Character limit hint
if content.count >= maxCharacters {
HStack(spacing: 4) {
Image(systemName: "exclamationmark.triangle")
.font(.caption)
.foregroundColor(.orange)
Text("max_characters_reached".localized)
.font(.caption)
.foregroundColor(.orange)
}
} else if content.count >= Int(Double(maxCharacters) * 0.93) {
HStack(spacing: 4) {
Image(systemName: "info.circle")
.font(.caption)
.foregroundColor(.blue)
Text("near_character_limit".localized)
.font(.caption)
.foregroundColor(.blue)
}
}
// Character count
Text(String(format: "character_count".localized, content.count, maxCharacters))
.font(.caption)
.foregroundColor(getCharacterCountColor())
}
}
}
}
private func getCharacterCountColor() -> Color {
if content.count >= maxCharacters {
return .orange
} else if content.count >= Int(Double(maxCharacters) * 0.93) {
return .blue
} else {
return .secondary
}
}
}
#Preview {
TextInputView(
content: .constant(""),
placeholder: "text_placeholder".localized,
maxCharacters: 150
)
}