From 37890e0c88f0cd5337b1c64db102ba205e7e00dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:55:29 -0500 Subject: [PATCH 01/55] updated icon to statusIcon and iconColorConfiguration Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 14 +++----- .../TextFields/EntryFieldBase.swift | 34 +++++++++++-------- .../TextFields/TextArea/TextArea.swift | 12 ++----- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 11550937..f1b7fd13 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -89,12 +89,6 @@ open class DropdownSelect: EntryFieldBase { // MARK: - Configuration Properties //-------------------------------------------------- internal override var containerSize: CGSize { CGSize(width: showInlineLabel ? minWidthInlineLabel : width ?? minWidthDefault, height: 44) } - - internal let iconColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .error) - } //-------------------------------------------------- // MARK: - Overrides @@ -240,11 +234,11 @@ open class DropdownSelect: EntryFieldBase { open override func updateErrorLabel() { super.updateErrorLabel() if !showError && !hasInternalError { - icon.name = .downCaret + statusIcon.name = .downCaret } - icon.surface = surface - icon.isHidden = readOnly ? true : false - icon.color = iconColorConfiguration.getColor(self) + statusIcon.surface = surface + statusIcon.isHidden = readOnly ? true : false + statusIcon.color = iconColorConfiguration.getColor(self) } @objc open func pickerDoneClicked() { diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 7ce12d75..7d78cf11 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -112,6 +112,12 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) } + internal let iconColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .error) + } + internal var readOnlyBorderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderReadonlyOnlight, VDSFormControlsColor.borderReadonlyOndark, forState: .normal) } @@ -142,7 +148,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.textStyle = .bodySmall } - open var icon: Icon = Icon().with { + open var statusIcon: Icon = Icon().with { $0.size = .medium } @@ -248,7 +254,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) - containerStackView.addArrangedSubview(icon) + containerStackView.addArrangedSubview(statusIcon) containerStackView.setCustomSpacing(VDSLayout.space3X, after: controlContainerView) //get the container this is what show helper text, error text @@ -379,32 +385,30 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else if hasInternalError, let internalErrorText { errorLabel.text = internalErrorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else { - icon.isHidden = true + statusIcon.isHidden = true errorLabel.isHidden = true } + statusIcon.color = iconColorConfiguration.getColor(self) } open func updateHelperLabel(){ diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index b8f0e009..797e7e74 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -138,12 +138,7 @@ open class TextArea: EntryFieldBase { setNeedsUpdate() } } - - /// Color configuration for error icon. - internal var iconColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) - } - + /// Color configuration for character counter's highlight background color internal var highlightBackgroundColor = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal) @@ -219,8 +214,7 @@ open class TextArea: EntryFieldBase { characterCounterLabel.text = getCharacterCounterText() - icon.size = .medium - icon.color = iconColorConfiguration.getColor(self) + statusIcon.color = iconColorConfiguration.getColor(self) containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor textView.isEditable = readOnly ? false : true textView.backgroundColor = backgroundColorConfiguration.getColor(self) @@ -240,7 +234,7 @@ open class TextArea: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() if showError { - accessibilityElements = [titleLabel, textView, icon, errorLabel, helperLabel] + accessibilityElements = [titleLabel, textView, statusIcon, errorLabel, helperLabel] } else { accessibilityElements = [titleLabel, textView, helperLabel] } From ca1e7e2b8751b836d8ce01f39c8cd594b3550989 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:55:41 -0500 Subject: [PATCH 02/55] added accessibleText Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/TextLinkModel.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/TextLinkModel.swift b/VDS/Components/TextFields/InputField/TextLinkModel.swift index d5d8c7ba..09abc023 100644 --- a/VDS/Components/TextFields/InputField/TextLinkModel.swift +++ b/VDS/Components/TextFields/InputField/TextLinkModel.swift @@ -12,12 +12,16 @@ extension InputField { ///Text that goes in the Tab public var text: String - + + ///Text that goes in the Tab + public var accessibleText: String? + ///Click event when you click on a tab public var onClick: ((TextLink) -> Void)? - public init(text: String, onClick: ((TextLink) -> Void)? = nil) { + public init(text: String, accessibleText: String? = nil, onClick: ((TextLink) -> Void)? = nil) { self.text = text + self.accessibleText = accessibleText self.onClick = onClick } } From 87389d02cc80183bad477e1538dc78030da8c5e2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:56:25 -0500 Subject: [PATCH 03/55] accessibleText update Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index f91d45ef..be05bbf2 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -52,7 +52,7 @@ open class Notification: View { } } - var accessibilityText: String { + var accessibleText: String { switch self { case .info: "Information Message" @@ -325,7 +325,7 @@ open class Notification: View { let iconColor = surface == .dark ? VDSColor.paletteWhite : VDSColor.paletteBlack typeIcon.name = style.iconName typeIcon.color = iconColor - typeIcon.accessibilityLabel = style.accessibilityText + typeIcon.accessibilityLabel = style.accessibleText closeButton.color = iconColor closeButton.isHidden = hideCloseButton } From 63de916555f32de159dca447acdda3ea30af79dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:56:53 -0500 Subject: [PATCH 04/55] initial rework for inputField Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 134 +++++++++++------- 1 file changed, 86 insertions(+), 48 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 004b33ae..bb1831cf 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -42,7 +42,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var inputFieldStackView: UIStackView = { + internal var inputFieldStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal @@ -77,9 +77,11 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { /// Representing the type of input. open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } - internal var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } + open var leftIcon: Icon = Icon().with { $0.size = .medium } - internal var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } + open var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } + + open var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } /// The text of this TextField. private var _text: String? @@ -155,13 +157,18 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) minWidthConstraint?.isActive = true - controlContainerView.addSubview(textField) - textField - .pinTop() - .pinLeading() - .pinTrailingLessThanOrEqualTo(nil, 0, .defaultHigh) - .pinBottom(0, .defaultHigh) + // stackview for controls in EntryFieldBase.controlContainerView + let controlStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.spacing = VDSLayout.space3X + } + controlContainerView.addSubview(controlStackView) + controlStackView.pinToSuperView() + controlStackView.addArrangedSubview(leftIcon) + controlStackView.addArrangedSubview(textField) + textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher @@ -210,16 +217,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField.isEnabled = isEnabled textField.textColor = textFieldTextColorConfiguration.getColor(self) - - if let actionTextLinkModel { - actionTextLink.text = actionTextLinkModel.text - actionTextLink.onClick = actionTextLinkModel.onClick - actionTextLink.isHidden = false - containerStackView.setCustomSpacing(VDSLayout.space2X, after: icon) - } else { - actionTextLink.isHidden = true - containerStackView.setCustomSpacing(0, after: icon) - } + + updateFieldType() //show error or success if showError, let _ = errorText { @@ -231,25 +230,14 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { successLabel.isEnabled = isEnabled successLabel.isHidden = false errorLabel.isHidden = true - icon.name = .checkmarkAlt - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .checkmarkAlt + statusIcon.color = VDSColor.paletteBlack + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else { - icon.isHidden = true + statusIcon.isHidden = true successLabel.isHidden = true } - - //set the width constraints - if let width, width > fieldType.width { - widthConstraint?.constant = width - widthConstraint?.isActive = true - minWidthConstraint?.isActive = false - } else { - minWidthConstraint?.constant = fieldType.width - widthConstraint?.isActive = false - minWidthConstraint?.isActive = true - } } open override func updateHelperLabel(){ @@ -272,25 +260,75 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } } -} - -extension InputField.FieldType { - var width: CGFloat { - switch self { + open func updateFieldType() { + textField.isSecureTextEntry = false + + var minWidth: CGFloat = 40.0 + var iconName: Icon.Name? + var actionLinkModel: InputField.TextLinkModel? + var toolTipModel: Tooltip.TooltipModel? + + switch fieldType { + case .text: + break + + case .number: + break + + case .calendar: + break + case .inlineAction: - return 102 + minWidth = 102.0 + case .password: - return 62.0 + textField.isSecureTextEntry = true + minWidth = 62.0 + case .creditCard: - return 288.0 + minWidth = 288.0 + case .tel: - return 176.0 + minWidth = 176.0 + case .date: - return 114.0 + minWidth = 114.0 + case .securityCode: - return 88.0 - default: - return 40.0 + minWidth = 88.0 + } + + //leftIcon + leftIcon.surface = surface + leftIcon.color = iconColorConfiguration.getColor(self) + leftIcon.name = iconName + leftIcon.isHidden = iconName == nil + + //actionLink + actionTextLink.surface = surface + if let actionTextLinkModel = actionLinkModel { + actionTextLink.text = actionTextLinkModel.text + actionTextLink.accessibilityLabel = actionTextLinkModel.accessibleText + actionTextLink.isHidden = false + containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) + } else { + actionTextLink.isHidden = true + containerStackView.setCustomSpacing(0, after: statusIcon) + } + + //set the width constraints + if let width, width > minWidth { + widthConstraint?.constant = width + widthConstraint?.isActive = true + minWidthConstraint?.isActive = false + } else { + minWidthConstraint?.constant = minWidth + widthConstraint?.isActive = false + minWidthConstraint?.isActive = true + } + + //tooltip + self.tooltipModel = toolTipModel } } From 7e2fdb30e3d1c0e433ec96f29432b8b5d3562f70 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 15:03:08 -0500 Subject: [PATCH 05/55] removed accessibleText Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/InputField.swift | 1 - VDS/Components/TextFields/InputField/TextLinkModel.swift | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index bb1831cf..cb013856 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -309,7 +309,6 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { actionTextLink.surface = surface if let actionTextLinkModel = actionLinkModel { actionTextLink.text = actionTextLinkModel.text - actionTextLink.accessibilityLabel = actionTextLinkModel.accessibleText actionTextLink.isHidden = false containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) } else { diff --git a/VDS/Components/TextFields/InputField/TextLinkModel.swift b/VDS/Components/TextFields/InputField/TextLinkModel.swift index 09abc023..89235e5e 100644 --- a/VDS/Components/TextFields/InputField/TextLinkModel.swift +++ b/VDS/Components/TextFields/InputField/TextLinkModel.swift @@ -13,15 +13,11 @@ extension InputField { ///Text that goes in the Tab public var text: String - ///Text that goes in the Tab - public var accessibleText: String? - ///Click event when you click on a tab public var onClick: ((TextLink) -> Void)? - public init(text: String, accessibleText: String? = nil, onClick: ((TextLink) -> Void)? = nil) { + public init(text: String, onClick: ((TextLink) -> Void)? = nil) { self.text = text - self.accessibleText = accessibleText self.onClick = onClick } } From bb705d8155e3197eef335b8a7e1b6aa426881014 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 23 Apr 2024 16:39:50 -0500 Subject: [PATCH 06/55] refactored value to be readOnly Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 7 +- .../TextFields/EntryFieldBase.swift | 10 +-- .../TextFields/InputField/InputField.swift | 90 +++++++++++-------- .../TextFields/TextArea/TextArea.swift | 14 +-- VDS/Protocols/FormFieldable.swift | 2 +- 5 files changed, 64 insertions(+), 59 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index f1b7fd13..860b4db0 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -37,6 +37,11 @@ open class DropdownSelect: EntryFieldBase { /// Allows unique ID to be passed to the element. open var selectId: Int? { didSet { setNeedsUpdate() }} + /// Current SelectedItem Value + open override var value: String? { + selectedItem?.value + } + /// Current SelectedItem open var selectedItem: DropdownOptionModel? { guard let selectId else { return nil } @@ -228,7 +233,6 @@ open class DropdownSelect: EntryFieldBase { open func updateSelectedOptionLabel(option: DropdownOptionModel? = nil) { selectedOptionLabel.text = option?.text ?? "" - value = option?.value } open override func updateErrorLabel() { @@ -278,6 +282,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { guard options.count > row else { return } selectId = row updateSelectedOptionLabel(option: options[row]) + sendActions(for: .valueChanged) self.onItemSelected?(row, options[row]) } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 7d78cf11..ddbd0016 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -201,15 +201,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var inputId: String? { didSet { setNeedsUpdate() } } /// The text of this textField. - internal var _value: String? open var value: String? { - get { _value } - set { - if let newValue, newValue != _value { - _value = newValue - sendActions(for: .valueChanged) - } - } + get { fatalError("must be read from subclass")} } open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } @@ -306,7 +299,6 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { transparentBackground = false width = nil inputId = nil - value = nil defaultValue = nil required = false readOnly = false diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index cb013856..f43fc951 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -30,15 +30,15 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { public required init?(coder: NSCoder) { super.init(coder: coder) } - + //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- /// Enum used to describe the input type. public enum FieldType: String, CaseIterable { - case text, number, calendar, inlineAction, password, creditCard, tel, date, securityCode + case text, number, inlineAction, password, creditCard, tel, date, securityCode } - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -50,9 +50,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { $0.spacing = 12 } }() - + internal var minWidthConstraint: NSLayoutConstraint? - + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -73,39 +73,29 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable() - + /// Representing the type of input. open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } - + open var leftIcon: Icon = Icon().with { $0.size = .medium } open var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } open var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } - + /// The text of this TextField. - private var _text: String? open var text: String? { - get { _text } + get { textField.text } set { - if let newValue, newValue != _text { - _text = newValue - textField.text = newValue - value = newValue - } - setNeedsUpdate() + textField.text = newValue } } - /// The value of this textField. + /// Value for the textField open override var value: String? { - didSet { - if text != value { - text = value - } - } + textField.text } - + var _showError: Bool = false /// Whether not to show the error. open override var showError: Bool { @@ -172,10 +162,10 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher - .sink { [weak self] text in - self?.value = text + .sink { [weak self] newText in + self?.text = newText self?.sendActions(for: .valueChanged) - + if newText.isEmpty { self?.passwordActionType = .show } }.store(in: &subscribers) stackView.addArrangedSubview(successLabel) @@ -259,13 +249,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } } } - + open func updateFieldType() { textField.isSecureTextEntry = false var minWidth: CGFloat = 40.0 - var iconName: Icon.Name? - var actionLinkModel: InputField.TextLinkModel? + var leftIconName: Icon.Name? + var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? switch fieldType { @@ -275,14 +265,22 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { case .number: break - case .calendar: - break - case .inlineAction: minWidth = 102.0 case .password: - textField.isSecureTextEntry = true + let isHide = passwordActionType == .hide + let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText + let isSecureTextEntry = !isHide + let nextPasswordActionType = passwordActionType.toggle() + if let text, !text.isEmpty { + actionModel = .init(text: buttonText, + onClick: { [weak self] _ in + guard let self else { return } + self.passwordActionType = nextPasswordActionType + }) + textField.isSecureTextEntry = isSecureTextEntry + } minWidth = 62.0 case .creditCard: @@ -302,13 +300,14 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //leftIcon leftIcon.surface = surface leftIcon.color = iconColorConfiguration.getColor(self) - leftIcon.name = iconName - leftIcon.isHidden = iconName == nil + leftIcon.name = leftIconName + leftIcon.isHidden = leftIconName == nil //actionLink actionTextLink.surface = surface - if let actionTextLinkModel = actionLinkModel { - actionTextLink.text = actionTextLinkModel.text + if let actionModel { + actionTextLink.text = actionModel.text + actionTextLink.onClick = actionModel.onClick actionTextLink.isHidden = false containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) } else { @@ -330,4 +329,21 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //tooltip self.tooltipModel = toolTipModel } + + //-------------------------------------------------- + // MARK: - Password + //-------------------------------------------------- + enum PasswordAction { + case show, hide + + func toggle() -> PasswordAction { + self == .hide ? .show : .hide + } + } + + internal var passwordActionType: PasswordAction = .show { didSet { setNeedsUpdate() } } + + open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } } + open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } + diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 797e7e74..1de4c1aa 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -102,24 +102,16 @@ open class TextArea: EntryFieldBase { /// The text of this TextArea. private var _text: String? open var text: String? { - get { _text } + get { textView.text } set { - if let newValue, newValue != _text { - _text = newValue - textView.text = newValue - value = newValue - } + textView.text = newValue setNeedsUpdate() } } /// The value of this textField. open override var value: String? { - didSet { - if text != value { - text = value - } - } + return textView.text } /// UITextView shown in the TextArea. diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 70a69ee5..83638cf4 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -15,7 +15,7 @@ public protocol FormFieldable { var inputId: String? { get set } /// Value for the Form Field. - var value: ValueType? { get set } + var value: ValueType? { get } } /// Protocol for FormFieldable that require internal validation. From 68d21296a7a76f588b76ff1b9f640c74dcfe8972 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 29 Apr 2024 15:16:56 -0500 Subject: [PATCH 07/55] Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorGroupBase.swift | 6 +++--- VDS/BaseClasses/Selector/SelectorItemBase.swift | 7 ++++--- VDS/Components/Checkbox/CheckboxGroup.swift | 9 +++++++-- VDS/Components/Icon/ButtonIcon/ButtonIcon.swift | 6 +----- VDS/Components/RadioBox/RadioBoxGroup.swift | 5 +++++ VDS/Components/RadioBox/RadioBoxItem.swift | 6 ++++-- VDS/Components/RadioButton/RadioButtonGroup.swift | 8 ++++++-- VDS/Components/Toggle/Toggle.swift | 3 +-- VDS/Components/Toggle/ToggleView.swift | 3 +-- 9 files changed, 32 insertions(+), 21 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorGroupBase.swift b/VDS/BaseClasses/Selector/SelectorGroupBase.swift index 997a71b2..1639ab86 100644 --- a/VDS/BaseClasses/Selector/SelectorGroupBase.swift +++ b/VDS/BaseClasses/Selector/SelectorGroupBase.swift @@ -20,7 +20,7 @@ extension SelectorGroup { public var hasSelectedItem: Bool { items.filter { $0.isSelected == true }.count > 0 } } -public protocol SelectorGroupMultiSelect: SelectorGroup {} +public protocol SelectorGroupMultiSelect: SelectorGroup, FormFieldable {} extension SelectorGroupMultiSelect { /// Current Selected Control for this group. public var selectedItems: [SelectorItemType]? { @@ -30,7 +30,7 @@ extension SelectorGroupMultiSelect { } } -public protocol SelectorGroupSingleSelect: SelectorGroup {} +public protocol SelectorGroupSingleSelect: SelectorGroup, FormFieldable {} extension SelectorGroupSingleSelect { /// Current Selected Control for this group. public var selectedItem: SelectorItemType? { @@ -39,7 +39,7 @@ extension SelectorGroupSingleSelect { } /// Base Class used for any Grouped Form Control of a Selector Type. -open class SelectorGroupBase: Control, SelectorGroup, Changeable { +open class SelectorGroupBase: Control, SelectorGroup, Changeable { //-------------------------------------------------- // MARK: - Private Properties diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 9eee8f29..6a45e5e8 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -11,7 +11,7 @@ import Combine import VDSTokens /// Base Class used to build out a SelectorControlable control. -open class SelectorItemBase: Control, Errorable, Changeable, FormFieldable { +open class SelectorItemBase: Control, Errorable, Changeable { //-------------------------------------------------- // MARK: - Initializers @@ -141,8 +141,10 @@ open class SelectorItemBase: Control, Errorable, open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { hiddenValue } + open var hiddenValue: AnyHashable? { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -214,7 +216,6 @@ open class SelectorItemBase: Control, Errorable, showError = false errorText = nil inputId = nil - value = nil isSelected = false onChange = nil diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index c7e424a1..1df8d9cd 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -14,6 +14,7 @@ import VDSTokens /// to allow user selection. @objc(VDSCheckboxGroup) open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSelect { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -32,6 +33,10 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: [SelectorItemType]? { selectedItems } + /// Array of ``CheckboxItemModel`` that will be used to build the selectorViews of type ``CheckboxItem``. open var selectorModels: [CheckboxItemModel]? { didSet { @@ -41,7 +46,7 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId - $0.value = model.value + $0.hiddenValue = model.value $0.accessibilityLabel = model.accessibileText $0.accessibilityValue = "item \(index+1) of \(selectorModels.count)" $0.labelText = model.labelText @@ -97,7 +102,7 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel } extension CheckboxGroup { - public struct CheckboxItemModel : Surfaceable, Initable, FormFieldable, Errorable { + public struct CheckboxItemModel : Surfaceable, Initable, Errorable { /// Whether this object is disabled or not public var disabled: Bool diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 658cb05e..b97a1fac 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -14,7 +14,7 @@ import Combine /// It usually represents a supplementary or utilitarian action. A button icon can stand alone, but often /// exists in a group when there are several actions that can be performed. @objc(VDSButtonIcon) -open class ButtonIcon: Control, Changeable, FormFieldable { +open class ButtonIcon: Control, Changeable { //-------------------------------------------------- // MARK: - Initializers @@ -173,10 +173,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable { /// Used to move the icon inside the button in both x and y axis. open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } } - open var inputId: String? { didSet { setNeedsUpdate() } } - - open var value: AnyHashable? { didSet { setNeedsUpdate() } } - //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index b31bcb0e..22e43426 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -32,6 +32,10 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: SelectorItemType? { selectedItem } + /// Array of ``RadioBoxItemModel`` that will be used to build the selectorViews of type ``RadioBoxItem``. open var selectorModels: [RadioBoxItemModel]? { didSet { @@ -48,6 +52,7 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe $0.subTextRightAttributes = model.subTextRightAttributes $0.isEnabled = !model.disabled $0.inputId = model.inputId + $0.hiddenValue = model.value $0.isSelected = model.selected } } diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 17d509c2..7828ed3c 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -125,7 +125,9 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { hiddenValue } + + open var hiddenValue: AnyHashable? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration Properties @@ -209,7 +211,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { subTextRightAttributedText = nil strikethrough = false inputId = nil - value = nil + hiddenValue = nil isSelected = false onChange = nil diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 6b12f60a..aecb8034 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -32,6 +32,10 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: SelectorItemType? { selectedItem } + /// Array of ``RadioButtonItemModel`` that will be used to build the selectorViews of type ``RadioButtonItem``. open var selectorModels: [RadioButtonItemModel]? { didSet { @@ -41,7 +45,7 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId - $0.value = model.value + $0.hiddenValue = model.value $0.accessibilityLabel = model.accessibileText $0.accessibilityValue = "item \(index+1) of \(selectorModels.count)" $0.labelText = model.labelText @@ -57,7 +61,7 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi setNeedsUpdate() } } - + private var _showError: Bool = false /// Whether not to show the error. diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index b73630d6..812d47d0 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -145,7 +145,7 @@ open class Toggle: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { isOn } /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { @@ -224,7 +224,6 @@ open class Toggle: Control, Changeable, FormFieldable { textWeight = .regular textPosition = .left inputId = nil - value = nil onChange = nil shouldUpdateView = true setNeedsUpdate() diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index 16b8307e..8faf4def 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -68,7 +68,7 @@ open class ToggleView: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { isOn } /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { toggleSize } @@ -163,7 +163,6 @@ open class ToggleView: Control, Changeable, FormFieldable { isOn = false isAnimated = true inputId = nil - value = nil toggleView.backgroundColor = toggleColorConfiguration.getColor(self) knobView.backgroundColor = knobColorConfiguration.getColor(self) onChange = nil From 39107082e7b6e8501d6def6cd2335a72e85a2814 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 29 Apr 2024 16:25:55 -0500 Subject: [PATCH 08/55] fixed bug with isSecureTextEntry Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f43fc951..db722165 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -63,7 +63,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } /// UITextField shown in the InputField. - open var textField = UITextField().with { + open var textField = TextField().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.font = TextStyle.bodyLarge.font } @@ -88,6 +88,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { get { textField.text } set { textField.text = newValue + setNeedsUpdate() } } @@ -163,9 +164,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField .textPublisher .sink { [weak self] newText in + print("textPublisher newText: \(newText)") self?.text = newText self?.sendActions(for: .valueChanged) - if newText.isEmpty { self?.passwordActionType = .show } }.store(in: &subscribers) stackView.addArrangedSubview(successLabel) @@ -251,13 +252,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } open func updateFieldType() { - textField.isSecureTextEntry = false var minWidth: CGFloat = 40.0 var leftIconName: Icon.Name? var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? - + var isSecureTextEntry = false + switch fieldType { case .text: break @@ -271,7 +272,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { case .password: let isHide = passwordActionType == .hide let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText - let isSecureTextEntry = !isHide + isSecureTextEntry = !isHide let nextPasswordActionType = passwordActionType.toggle() if let text, !text.isEmpty { actionModel = .init(text: buttonText, @@ -279,7 +280,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { guard let self else { return } self.passwordActionType = nextPasswordActionType }) - textField.isSecureTextEntry = isSecureTextEntry + } else { + passwordActionType = .show } minWidth = 62.0 @@ -297,6 +299,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } + //textField + textField.isSecureTextEntry = isSecureTextEntry + //leftIcon leftIcon.surface = surface leftIcon.color = iconColorConfiguration.getColor(self) @@ -327,7 +332,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } //tooltip - self.tooltipModel = toolTipModel + tooltipModel = toolTipModel } //-------------------------------------------------- @@ -347,3 +352,22 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } +public class TextField: UITextField { + + open override var isSecureTextEntry: Bool { + didSet { + if isFirstResponder { + _ = becomeFirstResponder() + } + } + } + + public override func becomeFirstResponder() -> Bool { + let success = super.becomeFirstResponder() + if isSecureTextEntry, let text { + self.text?.removeAll() + insertText(text) + } + return success + } +} From 5a0018319fb20cef51f117f09d26250971899ea2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 11:54:12 -0500 Subject: [PATCH 09/55] CXTDT-552068 - Text Area - Text padding Signed-off-by: Matt Bruce --- VDS/Components/TextFields/TextArea/TextArea.swift | 2 ++ VDS/SupportingFiles/ReleaseNotes.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index d057333b..732ac7ac 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -127,6 +127,8 @@ open class TextArea: EntryFieldBase { $0.translatesAutoresizingMaskIntoConstraints = false $0.sizeToFit() $0.isScrollEnabled = false + $0.textContainerInset = .zero + $0.textContainer.lineFragmentPadding = 0 } open var maxLength: Int? { diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 855ef058..3e3f0258 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,7 @@ +1.0.61 +---------------- +- CXTDT-552068 - Text Area - Text padding + 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 000e4cdefae703a5e03df87975788b188f8f0357 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 12:15:43 -0500 Subject: [PATCH 10/55] CXTDT-552074 - Text Area - Tooltip Signed-off-by: Matt Bruce --- .../Label/Attributes/TooltipLabelAttribute.swift | 8 +++++--- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 187d4eda..20666b10 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -37,17 +37,19 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable } var frame = CGRect.zero + let ratio: Double = 1.0 //0.80 + let yPosition: Double = -3 if let font = attributedString.attribute(.font, at: 0, effectiveRange: &originalRange) as? UIFont { switch font.pointSize { case 15..<25: size = .medium - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width * 0.80, height: size.value.dimensions.height * 0.80) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width * ratio, height: size.value.dimensions.height * ratio) case 0..<14: size = .small - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width * 0.80 , height: size.value.dimensions.height * 0.80) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width * ratio , height: size.value.dimensions.height * ratio) default: size = .medium - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width, height: size.value.dimensions.height) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width, height: size.value.dimensions.height) } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 3e3f0258..e09e37c0 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,6 +1,7 @@ 1.0.61 ---------------- - CXTDT-552068 - Text Area - Text padding +- CXTDT-552074 - Text Area - Tooltip 1.0.60 ---------------- From b80dcda680264d0b71f5c4c2e109d2e6975ca70e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 12:31:55 -0500 Subject: [PATCH 11/55] CXTDT-552070 - Text Area - Container heights Signed-off-by: Matt Bruce --- VDS/Components/TextFields/EntryFieldBase.swift | 2 +- VDS/Components/TextFields/TextArea/TextArea.swift | 9 +++++---- VDS/SupportingFiles/ReleaseNotes.txt | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index a8ad917a..2fae06c0 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -239,7 +239,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //this is the horizontal stack that contains //the left, InputContainer, Icons, Buttons container.addSubview(containerStackView) - containerStackView.pinToSuperView(.uniform(12)) + containerStackView.pinToSuperView(.uniform(VDSLayout.space3X)) //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 732ac7ac..83f940bb 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -86,15 +86,16 @@ open class TextArea: EntryFieldBase { case twoX = "2X" case fourX = "4X" case eightX = "8X" + var containerVerticalPadding: CGFloat { VDSLayout.space3X * 2 } var value: CGFloat { switch self { case .twoX: - 88 + 88 - containerVerticalPadding case .fourX: - 176 + 176 - containerVerticalPadding case .eightX: - 352 + 352 - containerVerticalPadding } } } @@ -176,7 +177,7 @@ open class TextArea: EntryFieldBase { .pinBottom(0, .defaultHigh) textView.isScrollEnabled = true textView.autocorrectionType = .no - textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) + textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: Height.twoX.value) textViewHeightConstraint?.isActive = true backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index e09e37c0..1df8f3a6 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -2,7 +2,7 @@ ---------------- - CXTDT-552068 - Text Area - Text padding - CXTDT-552074 - Text Area - Tooltip - +- CXTDT-552070 - Text Area - Container heights 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 83e0c4ab53fe249ea7e0a8cb28ea23cc9f562c82 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:15:31 -0500 Subject: [PATCH 12/55] CXTDT-552071 - Text Area - Entering text Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldBase.swift | 1 + .../TextFields/TextArea/TextArea.swift | 23 +++++++++++++++++-- VDS/SupportingFiles/ReleaseNotes.txt | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 2fae06c0..2f776ab8 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -107,6 +107,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { internal var borderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: .focused) $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]) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 83f940bb..ad76b0f2 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -79,7 +79,18 @@ open class TextArea: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - override var containerSize: CGSize { CGSize(width: 182, height: 88) } + /// Override UIControl state to add the .error state if showSuccess is true and if showError is true. + open override var state: UIControl.State { + get { + var state = super.state + if textView.isFirstResponder && !showError && !hasInternalError { + state.insert(.focused) + } + return state + } + } + + override var containerSize: CGSize { CGSize(width: 182, height: Height.twoX.value) } /// Enum used to describe the the height of TextArea. public enum Height: String, CaseIterable { @@ -177,7 +188,7 @@ open class TextArea: EntryFieldBase { .pinBottom(0, .defaultHigh) textView.isScrollEnabled = true textView.autocorrectionType = .no - textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: Height.twoX.value) + textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) textViewHeightConstraint?.isActive = true backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) @@ -309,6 +320,14 @@ open class TextArea: EntryFieldBase { } extension TextArea: UITextViewDelegate { + public func textViewDidBeginEditing(_ textView: UITextView) { + setNeedsUpdate() + } + + public func textViewDidEndEditing(_ textView: UITextView) { + setNeedsUpdate() + } + //-------------------------------------------------- // MARK: - UITextViewDelegate //-------------------------------------------------- diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 1df8f3a6..8ffb31cb 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -3,6 +3,8 @@ - CXTDT-552068 - Text Area - Text padding - CXTDT-552074 - Text Area - Tooltip - CXTDT-552070 - Text Area - Container heights +- CXTDT-552071 - Text Area - Entering text + 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 896d393d7a4dd7ba53e33760610a123036414573 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:24:37 -0500 Subject: [PATCH 13/55] updated for focused Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 62b361c6..f18a6224 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -14,7 +14,7 @@ import Combine /// Specialized input fields capture credit card numbers, inline actions, passwords, phone numbers, /// dates and security codes in their correct formats. @objc(VDSInputField) -open class InputField: EntryFieldBase, UITextFieldDelegate { +open class InputField: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers @@ -127,7 +127,11 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { var state = super.state if showSuccess { state.insert(.success) + + } else if textField.isFirstResponder && !showError && !hasInternalError { + state.insert(.focused) } + return state } } @@ -160,7 +164,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { controlStackView.addArrangedSubview(leftIcon) controlStackView.addArrangedSubview(textField) - + + textField.delegate = self textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher @@ -373,6 +378,16 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } +extension InputField: UITextFieldDelegate { + public func textFieldDidBeginEditing(_ textField: UITextField) { + setNeedsUpdate() + } + + public func textFieldDidEndEditing(_ textField: UITextField) { + setNeedsUpdate() + } +} + public class TextField: UITextField { open override var isSecureTextEntry: Bool { From aa4dc91afabc0c7e2e575ecbaaca2a67fec53fc1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:51:13 -0500 Subject: [PATCH 14/55] updated for password field Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/InputField.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f18a6224..9200a5f7 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -262,7 +262,7 @@ open class InputField: EntryFieldBase { var minWidth: CGFloat = 40.0 var leftIconName: Icon.Name? var actionModel: InputField.TextLinkModel? - var toolTipModel: Tooltip.TooltipModel? + var toolTipModel: Tooltip.TooltipModel? = tooltipModel var isSecureTextEntry = false switch fieldType { @@ -277,7 +277,10 @@ open class InputField: EntryFieldBase { case .password: let isHide = passwordActionType == .hide - let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText + let buttonText = isHide ? + hidePasswordButtonText.isEmpty ? "Hide" : hidePasswordButtonText : + showPasswordButtonText.isEmpty ? "Show" : showPasswordButtonText + isSecureTextEntry = !isHide let nextPasswordActionType = passwordActionType.toggle() if let text, !text.isEmpty { From cfc21c2727b31f35cfbd892960501a751a7a8703 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 14:10:36 -0500 Subject: [PATCH 15/55] added internal rules Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../TextFields/Rules/CharacterCountRule.swift | 18 ++++++++++++++++++ .../TextFields/Rules/RequiredRule.swift | 19 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 VDS/Components/TextFields/Rules/CharacterCountRule.swift create mode 100644 VDS/Components/TextFields/Rules/RequiredRule.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 308c7f47..ccc8e61d 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -54,6 +54,8 @@ EA21C5DB2B600EDE00CFC139 /* VDSTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */; }; EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; }; EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */; }; + EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; }; + EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */; }; EA336171288B19200071C351 /* VDS.docc in Sources */ = {isa = PBXBuildFile; fileRef = EA336170288B19200071C351 /* VDS.docc */; }; EA336177288B19210071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33616C288B19200071C351 /* VDS.framework */; }; EA33617C288B19210071C351 /* VDSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33617B288B19210071C351 /* VDSTests.swift */; }; @@ -243,6 +245,8 @@ EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = ""; }; EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = ""; }; EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesTouchable.swift; sourceTree = ""; }; + EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = ""; }; + EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCountRule.swift; sourceTree = ""; }; EA33616C288B19200071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA33616F288B19200071C351 /* VDS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VDS.h; sourceTree = ""; }; EA336170288B19200071C351 /* VDS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = VDS.docc; sourceTree = ""; }; @@ -512,6 +516,15 @@ path = ButtonGroup; sourceTree = ""; }; + EA2DC9AE2BE175A6004F58C5 /* Rules */ = { + isa = PBXGroup; + children = ( + EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */, + EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */, + ); + path = Rules; + sourceTree = ""; + }; EA336162288B19200071C351 = { isa = PBXGroup; children = ( @@ -875,6 +888,7 @@ EAC925852911C9DE00091998 /* TextFields */ = { isa = PBXGroup; children = ( + EA2DC9AE2BE175A6004F58C5 /* Rules */, EAC9258B2911C9DE00091998 /* EntryFieldBase.swift */, EAC925862911C9DE00091998 /* InputField */, EA985C21296E032000F2FF2E /* TextArea */, @@ -1136,6 +1150,7 @@ 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */, EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */, EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */, + EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */, EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */, 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, @@ -1145,6 +1160,7 @@ 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, EA985BEA29689B6D00F2FF2E /* TileletSubTitleModel.swift in Sources */, + EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */, EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */, EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */, EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */, diff --git a/VDS/Components/TextFields/Rules/CharacterCountRule.swift b/VDS/Components/TextFields/Rules/CharacterCountRule.swift new file mode 100644 index 00000000..f26ccafc --- /dev/null +++ b/VDS/Components/TextFields/Rules/CharacterCountRule.swift @@ -0,0 +1,18 @@ +// +// CharacterCountRule.swift +// VDS +// +// Created by Matt Bruce on 4/30/24. +// + +import Foundation + +class CharacterCountRule: Rule { + var maxLength: Int? + var errorMessage: String = "You have exceeded the character limit." + + func isValid(value: String?) -> Bool { + guard let text = value, let maxLength, maxLength > 0 else { return true } + return text.count <= maxLength + } +} diff --git a/VDS/Components/TextFields/Rules/RequiredRule.swift b/VDS/Components/TextFields/Rules/RequiredRule.swift new file mode 100644 index 00000000..df00bc59 --- /dev/null +++ b/VDS/Components/TextFields/Rules/RequiredRule.swift @@ -0,0 +1,19 @@ +// +// RequiredRule.swift +// VDS +// +// Created by Matt Bruce on 4/30/24. +// + +import Foundation + +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 } + return true + } +} + From 1813661f7d7c4674f934926138edad2f7b3310ab Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 15:48:29 -0500 Subject: [PATCH 16/55] updated states Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldBase.swift | 59 ++++++++++++++----- .../TextFields/InputField/InputField.swift | 19 ++++-- .../TextFields/TextArea/TextArea.swift | 20 +++---- 3 files changed, 66 insertions(+), 32 deletions(-) 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