-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathValidationViewModifier.swift
More file actions
94 lines (83 loc) · 2.77 KB
/
ValidationViewModifier.swift
File metadata and controls
94 lines (83 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
// Validator
// Copyright © 2023 Space Code. All rights reserved.
//
import SwiftUI
import ValidatorCore
/// A validation view modifier.
///
/// The validation view modifier automatically tracks validation errors,
/// uses the content view builder to construct an error view, and displays
/// it to the user.
///
/// ```
/// struct ContentView: View {
/// @State private var text: String = "Text"
///
/// var body: some View {
/// VStack {
/// TextField("Title", text: $text)
/// .modifier(
/// ValidationViewModifier(
/// item: $text,
/// rules: [
/// LengthValidationRule(max: 10, error: "The error message"),
/// ],
/// content: { errors in
/// Text(errors.map { $0.message }.joined(separator: " "))
/// }
/// )
/// )
/// Spacer()
/// }
/// .padding()
/// }
/// }
/// ```
public struct ValidationViewModifier<T, ErrorView: View>: ViewModifier {
// MARK: Properties
/// The result of the validation.
@State private var validationResult: ValidationResult = .valid
/// The binding item to validate.
@Binding private var item: T
/// A custom parameter attribute that constructs views from closures.
@ViewBuilder private let content: ([any IValidationError]) -> ErrorView
/// The array of validation rules to apply to the item's value.
public let rules: [any IValidationRule<T>]
/// Creates a new instance of the `ValidationViewModifier`.
///
/// - Parameters:
/// - item: The binding item to validate.
/// - rules: The array of validation rules to apply to the item's value.
/// - content: A custom parameter attribute that constructs an error view from closures.
public init(
item: Binding<T>,
rules: [any IValidationRule<T>],
@ViewBuilder content: @escaping ([any IValidationError]) -> ErrorView
) {
_item = item
self.rules = rules
self.content = content
}
// MARK: ViewModifier
public func body(content: Content) -> some View {
VStack(alignment: .leading) {
content
.validation($item, rules: rules) { result in
DispatchQueue.main.async {
validationResult = result
}
}
validationMessageView
}
}
// MARK: Private
private var validationMessageView: some View {
switch validationResult {
case .valid:
EmptyView().eraseToAnyView()
case let .invalid(errors):
content(errors).eraseToAnyView()
}
}
}