TextField configuration extraction issue

52 Views Asked by At

how do I achieve the following?

I have a TextField, and I want to create a configuration for it so that I can reuse it multiple times.

I'm using formatting, which is important because it's causing an issue here. However, everything works correctly if I move the 'text' and 'error' properties and bind them as '@State' to the view or use them as an 'ObservableObject'.

Here, you can see the issue. I'm encountering an error, and when I start typing, the table should disappear, but the cursor shouldn't jump to the beginning if I want to continue editing.

Can you suggest how I can improve this struct, or should I consider working with a class that conforms to ObservableObject?

enter image description here

struct Config {
    @Binding public var text: String
    @Binding public var error: String?
    
    init(text: Binding<String>, error: Binding<String?>) {
        _text = text
        _error = error
    }
}

struct ContentView: View {
    var config: Config
    
    init(config: Config) {
        self.config = config
    }
    
    var body: some View {
        VStack {
            TextField("Enter text",
                      value: config.$text,
                      format: .numberFormatStyle)
            if let error = config.error {
                Text(error)
                    .foregroundStyle(.red)
            }
            
            Button("Validate") {
                if config.text != "ABC" {
                    config.error = "Not valid text"
                }
            }
        }
        .padding()
        .onChange(of: config.text) {
            config.error = nil
        }
    }
}

struct NumberParseStrategy: ParseStrategy {
    func parse(_ value: String) throws -> String {
        value
    }
}

struct NumberFormatStyle: ParseableFormatStyle {
    var parseStrategy: NumberParseStrategy { .init() }
    
    func format(_ value: String) -> String {
        value
            .lazy
            .filter { $0 != " " }
            .chunks(ofCount: 3)
            .map { String($0) }
            .joined(separator: "-")
    }
}

extension ParseableFormatStyle where Self == NumberFormatStyle {
    static var numberFormatStyle: NumberFormatStyle { .init() }
}

extension Array {
    func chunks(ofCount chunkCount: Int) -> [[Element]] {
        var result: [[Element]] = []
        for index in stride(from: 0, to: count, by: chunkCount) {
            let lastIdx = Swift.min(count, index + chunkCount)
            result.append(Array(self[index ..< lastIdx]))
        }
        return result
    }
}

@main
struct FormattedTextFIeldApp: App {
    @State var text = ""
    @State var error: String?
    
    var body: some Scene {
       
        WindowGroup {
            ContentView(config: Config(text: $text, error: $error))
        }
    }
}
0

There are 0 best solutions below