diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 63f0ca69..390c2b9a 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -83,6 +83,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } }() + open var rules = [AnyRule]() + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -103,11 +105,13 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: [.error, .focused]) } internal var borderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: .focused) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: [.focused, .error]) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) @@ -159,7 +163,10 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { internal var validator: (any FormFieldValidatorable)? /// Whether or not to show the internal error - open var hasInternalError: Bool { !(validator?.isValid ?? true) } + open var hasInternalError: Bool { + guard let validator, !showError else { return false } + return !validator.isValid + } /// Override UIControl state to add the .error state if showError is true. open override var state: UIControl.State { @@ -304,15 +311,30 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - + updateRules() + validator = FormFieldValidator(field: self, rules: rules) + updateContainerView() updateTitleLabel() updateErrorLabel() updateHelperLabel() backgroundColor = surface.color - validator?.validate() - internalErrorText = validator?.errorMessage + + if let validator { + validator.validate() + if validator.isValid { + internalErrorText = nil + } else { + if let errorText, errorText.isEmpty { + internalErrorText = errorText + } else { + internalErrorText = validator.errorMessage + } + } + } else { + internalErrorText = nil + } } //-------------------------------------------------- @@ -338,6 +360,21 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { return bottomContainerView } + internal func updateRules() { + rules.removeAll() + if self.required { + let rule = RequiredRule() + if let errorText { + rule.errorMessage = errorText + } else if let labelText{ + rule.errorMessage = "You must enter a \(labelText)" + } else { + rule.errorMessage = "You must enter a value" + } + rules.append(.init(rule)) + } + } + open func updateTitleLabel() { //update the local vars for the label since we no @@ -369,22 +406,14 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } open func updateErrorLabel(){ - if showError, hasInternalError, let errorText, let internalErrorText { - errorLabel.text = [internalErrorText, errorText].joined(separator: "\n") - errorLabel.surface = surface - errorLabel.isEnabled = isEnabled - errorLabel.isHidden = false - statusIcon.name = .error - statusIcon.surface = surface - statusIcon.isHidden = !isEnabled - } else if showError, let errorText { + if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false statusIcon.name = .error statusIcon.surface = surface - statusIcon.isHidden = !isEnabled + statusIcon.isHidden = !isEnabled || state.contains(.focused) } else if hasInternalError, let internalErrorText { errorLabel.text = internalErrorText errorLabel.surface = surface @@ -392,7 +421,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { errorLabel.isHidden = false statusIcon.name = .error statusIcon.surface = surface - statusIcon.isHidden = !isEnabled + statusIcon.isHidden = !isEnabled || state.contains(.focused) } else { statusIcon.isHidden = true errorLabel.isHidden = true diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 9200a5f7..071790c5 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -210,13 +210,15 @@ open class InputField: EntryFieldBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { + + //update fieldType first + updateFieldType() + super.updateView() textField.isEnabled = isEnabled textField.textColor = textFieldTextColorConfiguration.getColor(self) - - updateFieldType() - + //show error or success if showError, let _ = errorText { successLabel.isHidden = true @@ -264,7 +266,16 @@ open class InputField: EntryFieldBase { var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? = tooltipModel var isSecureTextEntry = false - + var rules = [AnyRule]() + + if self.required { + let rule = RequiredRule() + if let errorText { + rule.errorMessage = errorText + } + rules.append(.init(rule)) + } + switch fieldType { case .text: break diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 796fe6cd..8dd9485a 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -83,7 +83,7 @@ open class TextArea: EntryFieldBase { open override var state: UIControl.State { get { var state = super.state - if textView.isFirstResponder && !showError && !hasInternalError { + if textView.isFirstResponder { state.insert(.focused) } return state @@ -162,8 +162,6 @@ open class TextArea: EntryFieldBase { open override func setup() { super.setup() isAccessibilityElement = false - validator = FormFieldValidator