diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index df7cc7c9..06381fab 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -6,7 +6,7 @@ import Combine /// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection. @objcMembers @objc(VDSDatePicker) -open class DatePicker: EntryFieldBase { +open class DatePicker: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 947210f4..d0ef7275 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -13,7 +13,7 @@ import Combine /// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection. @objcMembers @objc(VDSDropdownSelect) -open class DropdownSelect: EntryFieldBase { +open class DropdownSelect: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 63288e96..afb93dcb 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -10,9 +10,10 @@ import UIKit import VDSCoreTokens import Combine -/// A stepper is a two-segment control that people use to increase or decrease an incremental value. +/// A stepper is a two-segment control that people use to increase or decrease an incremental value.' +@objcMembers @objc(VDSInputStepper) -open class InputStepper: EntryFieldBase { +open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers @@ -70,6 +71,8 @@ open class InputStepper: EntryFieldBase { /// Allows an id to be passed to input stepper. open var id: Int? { didSet { setNeedsUpdate() } } + open override var value: Int? { return defaultValue } + /// Maximum value of the input stepper, defaults to '99'. open var maxValue: Int? = 99 { didSet { @@ -101,20 +104,9 @@ open class InputStepper: EntryFieldBase { /// Accepts any text or character to appear next to input stepper value. open var trailingText: String? { didSet { setNeedsUpdate() } } - /// Value for the textField - open override var value: String? { - return nil - } - //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - /// Default Int value of the input stepper, defaults to '0'. - internal var defaultIntValue: Int { - guard let intValue = defaultValue as? Int else { return 0 } - return intValue - } - /// This is the view that will be wrapped with the border for userInteraction. /// The only subview of this view is the stepperStackView. internal var stepperContainerView = View().with { @@ -186,6 +178,7 @@ open class InputStepper: EntryFieldBase { super.setup() // Set initial states + defaultValue = 0 containerView.isEnabled = false statusIcon.isHidden = true @@ -227,7 +220,7 @@ open class InputStepper: EntryFieldBase { statusIcon.isHidden = true // Update label text, style, color, ande surface. - textLabel.text = String(defaultIntValue) + " " + (trailingText ?? "") + textLabel.text = "\(value ?? 0) " + (trailingText ?? "") textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.surface = surface @@ -275,6 +268,7 @@ open class InputStepper: EntryFieldBase { controlWidthPercentage = nil widthPercentage = nil id = nil + defaultValue = 0 minValue = 0 maxValue = 99 trailingText = nil @@ -314,18 +308,18 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- internal func checkDefaultValue() { if let minValue, let maxValue { - defaultValue = defaultIntValue > maxValue ? maxValue : defaultIntValue < minValue ? minValue : defaultIntValue + defaultValue = defaultValue! > maxValue ? maxValue : defaultValue! < minValue ? minValue : defaultValue! } } internal func decrementButtonClick() { - defaultValue = defaultIntValue - 1 + defaultValue = defaultValue! - 1 checkDefaultValue() updateButtonStates() } internal func incrementButtonClick() { - defaultValue = defaultIntValue + 1 + defaultValue = defaultValue! + 1 checkDefaultValue() updateButtonStates() } @@ -340,8 +334,8 @@ open class InputStepper: EntryFieldBase { decrementButton.isEnabled = false incrementButton.isEnabled = false } else { - decrementButton.isEnabled = defaultIntValue > minValue ?? 0 ? true : false - incrementButton.isEnabled = defaultIntValue < maxValue ?? 99 ? true : false + decrementButton.isEnabled = defaultValue! > minValue ?? 0 ? true : false + incrementButton.isEnabled = defaultValue! < maxValue ?? 99 ? true : false } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 6b30c169..e492d6fa 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -11,10 +11,7 @@ import VDSCoreTokens import Combine /// Base Class used to build out a Input controls. -@objcMembers -@objc(VDSEntryField) -open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { - +open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -229,11 +226,11 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var inputId: String? { didSet { setNeedsUpdate() } } /// The text of this textField. - open var value: String? { + open var value: ValueType? { get { fatalError("must be read from subclass")} } - open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } + open var defaultValue: ValueType? { didSet { setNeedsUpdate() } } open var isRequired: Bool = false { didSet { setNeedsUpdate() } } @@ -245,7 +242,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } } - open var rules = [AnyRule]() + open var rules = [AnyRule]() open var accessibilityHintText: String = "Double tap to open" @@ -342,8 +339,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } containerView.bridge_accessibilityValueBlock = { [weak self] in - guard let self else { return "" } - return value + guard let self, let value else { return "" } + return "\(value)" } statusIcon.bridge_accessibilityLabelBlock = { [weak self] in @@ -523,8 +520,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //-------------------------------------------------- internal func updateRules() { rules.removeAll() - if isRequired && useRequiredRule { - let rule = RequiredRule() + if isRequired && useRequiredRule && ValueType.self == String.self { + let rule = RequiredRule() if let errorText, !errorText.isEmpty { rule.errorMessage = errorText } else if let labelText{ diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index a65df78e..675fc6ac 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -15,7 +15,7 @@ import Combine /// dates and security codes in their correct formats. @objcMembers @objc(VDSInputField) -open class InputField: EntryFieldBase { +open class InputField: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers diff --git a/VDS/Components/TextFields/Rules/RequiredRule.swift b/VDS/Components/TextFields/Rules/RequiredRule.swift index df00bc59..d4296036 100644 --- a/VDS/Components/TextFields/Rules/RequiredRule.swift +++ b/VDS/Components/TextFields/Rules/RequiredRule.swift @@ -7,12 +7,14 @@ import Foundation -class RequiredRule: Rule { +class RequiredRule: Rule { var maxLength: Int? var errorMessage: String = "This field is required." - func isValid(value: String?) -> Bool { - guard let value, !value.isEmpty, value.count > 0 else { return false } + func isValid(value: ValueType?) -> Bool { + guard let value, + !"\(value)".isEmpty, + "\(value)".count > 0 else { return false } return true } } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 07c79ca6..e9a714be 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -14,7 +14,7 @@ import Combine /// Use a text area when you want customers to enter text that’s longer than a single line. @objcMembers @objc(VDSTextArea) -open class TextArea: EntryFieldBase { +open class TextArea: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 82666772..98aa6ae8 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -8,7 +8,7 @@ import Foundation /// Protocol used for a FormField object. -public protocol FormFieldable { +public protocol FormFieldable { associatedtype ValueType = AnyHashable /// Unique Id for the Form Field object within a Form. @@ -19,7 +19,7 @@ public protocol FormFieldable { } /// Protocol for FormFieldable that require internal validation. -public protocol FormFieldInternalValidatable: FormFieldable, Errorable { +public protocol FormFieldInternalValidatable: FormFieldable, Errorable { /// Rules that drive the validator var rules: [AnyRule] { get set }