diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 182c1660..0488f0b2 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -7,10 +7,11 @@ import Foundation import UIKit +import Combine @objc(VDSTextField) -open class TextField: UITextField { - +open class TextField: UITextField, ViewProtocol, Errorable { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -28,33 +29,46 @@ open class TextField: UITextField { super.init(coder: coder) initialSetup() } - - var horizontalPadding: CGFloat = 0 - open override func textRect(forBounds bounds: CGRect) -> CGRect { - let rect = super.textRect(forBounds: bounds) - return rect.insetBy(dx: -horizontalPadding, dy: 0) - } - - open override func editingRect(forBounds bounds: CGRect) -> CGRect { - let rect = super.editingRect(forBounds: bounds) - return rect.insetBy(dx: -horizontalPadding, dy: 0) - } - - open override func placeholderRect(forBounds bounds: CGRect) -> CGRect { - let rect = super.placeholderRect(forBounds: bounds) - return rect.insetBy(dx: -horizontalPadding, dy: 0) - } + //-------------------------------------------------- + // MARK: - Combine Properties + //-------------------------------------------------- + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() - open override var isSecureTextEntry: Bool { - didSet { - if isFirstResponder { - _ = becomeFirstResponder() - } + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var initialSetupPerformed = false + + private var horizontalPadding: CGFloat = 0 + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + /// Key of whether or not updateView() is called in setNeedsUpdate() + open var shouldUpdateView: Bool = true + + open var surface: Surface = .light { didSet { setNeedsUpdate() } } + + open var showError: Bool = false { didSet { setNeedsUpdate() } } + + open var errorText: String? { didSet { setNeedsUpdate() } } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open func initialSetup() { + if !initialSetupPerformed { + initialSetupPerformed = true + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + setup() + setNeedsUpdate() } } - open func initialSetup() { + open func setup() { let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) accessView.backgroundColor = .white accessView.addBorder(side: .top, width: 1, color: .lightGray) @@ -72,6 +86,50 @@ open class TextField: UITextField { // Resigns the first responder status when 'Done' is tapped resignFirstResponder() } + + open func updateView() {} + + open func updateAccessibility() { + if let errorText, showError { + accessibilityLabel = "error, \(errorText)" + } else { + accessibilityLabel = nil + } + } + + open func reset() { + shouldUpdateView = false + surface = .light + text = nil + shouldUpdateView = true + setNeedsUpdate() + } + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override func textRect(forBounds bounds: CGRect) -> CGRect { + let rect = super.textRect(forBounds: bounds) + return rect.insetBy(dx: -horizontalPadding, dy: 0) + } + + open override func editingRect(forBounds bounds: CGRect) -> CGRect { + let rect = super.editingRect(forBounds: bounds) + return rect.insetBy(dx: -horizontalPadding, dy: 0) + } + + open override func placeholderRect(forBounds bounds: CGRect) -> CGRect { + let rect = super.placeholderRect(forBounds: bounds) + return rect.insetBy(dx: -horizontalPadding, dy: 0) + } + + open override var isSecureTextEntry: Bool { + didSet { + if isFirstResponder { + _ = becomeFirstResponder() + } + } + } open override func becomeFirstResponder() -> Bool { let success = super.becomeFirstResponder() diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index b1faae53..f0b64f46 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -11,7 +11,7 @@ import Combine import VDSTokens @objc(VDSTextView) -open class TextView: UITextView, ViewProtocol { +open class TextView: UITextView, ViewProtocol, Errorable { //-------------------------------------------------- // MARK: - Initializers @@ -66,6 +66,10 @@ open class TextView: UITextView, ViewProtocol { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable(){ didSet { setNeedsUpdate() }} + open var showError: Bool = false { didSet { setNeedsUpdate() } } + + open var errorText: String? { didSet { setNeedsUpdate() } } + open override var textColor: UIColor? { get { textColorConfiguration.getColor(self) } set { } @@ -102,7 +106,6 @@ open class TextView: UITextView, ViewProtocol { } } - open func setup() { let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) accessView.backgroundColor = .white @@ -126,7 +129,13 @@ open class TextView: UITextView, ViewProtocol { updateLabel() } - open func updateAccessibility() {} + open func updateAccessibility() { + if let errorText, showError { + accessibilityLabel = "error, \(errorText)" + } else { + accessibilityLabel = nil + } + } open func reset() { shouldUpdateView = false