diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 860b4db0..e86b3792 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -162,7 +162,7 @@ open class DropdownSelect: EntryFieldBase { updateInlineLabel() - dropdownField.isUserInteractionEnabled = readOnly ? false : true + dropdownField.isUserInteractionEnabled = isReadOnly ? false : true selectedOptionLabel.surface = surface selectedOptionLabel.isEnabled = isEnabled } @@ -190,7 +190,7 @@ open class DropdownSelect: EntryFieldBase { updatedLabelText = showInlineLabel ? "" : updatedLabelText - if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") { + if let oldText = updatedLabelText, !isRequired, !oldText.hasSuffix("Optional") { let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2, length: 8, color: secondaryColorConfiguration.getColor(self)) @@ -241,7 +241,7 @@ open class DropdownSelect: EntryFieldBase { statusIcon.name = .downCaret } statusIcon.surface = surface - statusIcon.isHidden = readOnly ? true : false + statusIcon.isHidden = isReadOnly ? true : false statusIcon.color = iconColorConfiguration.getColor(self) } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index daae8a66..644a8de1 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -190,9 +190,9 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } - open var required: Bool = false { didSet { validate() } } + open var isRequired: Bool = false { didSet { setNeedsUpdate() } } - open var readOnly: Bool = false { didSet { setNeedsUpdate() } } + open var isReadOnly: Bool = false { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Constraints @@ -283,8 +283,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { width = nil inputId = nil defaultValue = nil - required = false - readOnly = false + isRequired = false + isReadOnly = false onChange = nil } @@ -309,7 +309,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //-------------------------------------------------- private func updateContainerView() { containerView.backgroundColor = backgroundColorConfiguration.getColor(self) - containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor + containerView.layer.borderColor = isReadOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor containerView.layer.borderWidth = VDSFormControls.borderWidth containerView.layer.cornerRadius = VDSFormControls.borderRadius } @@ -329,7 +329,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { internal func updateRules() { rules.removeAll() - if self.required { + if self.isRequired { let rule = RequiredRule() if let errorText, !errorText.isEmpty { rule.errorMessage = errorText @@ -350,7 +350,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { var updatedLabelText = labelText //dealing with the "Optional" addition to the text - if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") { + if let oldText = updatedLabelText, !isRequired, !oldText.hasSuffix("Optional") { if isEnabled { let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2, length: 8, diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 5f8019e0..2b7fdab5 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -165,7 +165,6 @@ open class InputField: EntryFieldBase { controlStackView.addArrangedSubview(leftIcon) controlStackView.addArrangedSubview(textField) - textField.delegate = self textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher @@ -176,6 +175,18 @@ open class InputField: EntryFieldBase { self?.sendActions(for: .valueChanged) }.store(in: &subscribers) + textField + .publisher(for: .editingDidBegin) + .sink { [weak self] _ in + self?.setNeedsUpdate() + }.store(in: &subscribers) + + textField + .publisher(for: .editingDidEnd) + .sink { [weak self] _ in + self?.validate() + }.store(in: &subscribers) + stackView.addArrangedSubview(successLabel) stackView.setCustomSpacing(8, after: successLabel) @@ -192,7 +203,6 @@ open class InputField: EntryFieldBase { open override func reset() { super.reset() textField.text = "" - textField.delegate = self successLabel.reset() successLabel.textStyle = .bodySmall @@ -272,7 +282,7 @@ open class InputField: EntryFieldBase { var isSecureTextEntry = false var rules = [AnyRule]() - if self.required { + if self.isRequired { let rule = RequiredRule() if let errorText { rule.errorMessage = errorText @@ -395,33 +405,3 @@ open class InputField: EntryFieldBase { open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } } 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 { - didSet { - if isFirstResponder { - _ = becomeFirstResponder() - } - } - } - - public override func becomeFirstResponder() -> Bool { - let success = super.becomeFirstResponder() - if isSecureTextEntry, let text { - self.text?.removeAll() - insertText(text) - } - return success - } -} diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index f37c9d39..7229c4a9 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -60,7 +60,7 @@ open class TextArea: EntryFieldBase { $0.textAlignment = .right $0.numberOfLines = 1 } - + private var _minHeight: Height = .twoX open var minHeight: Height? { @@ -110,7 +110,7 @@ open class TextArea: EntryFieldBase { } } } - + /// The text of this TextArea. private var _text: String? open var text: String? { @@ -125,7 +125,7 @@ open class TextArea: EntryFieldBase { open override var value: String? { return textView.text } - + /// UITextView shown in the TextArea. open var textView = TextView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -144,12 +144,12 @@ open class TextArea: EntryFieldBase { validate() } } - + /// Color configuration for character counter's highlight background color internal var highlightBackgroundColor = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal) } - + /// Color configuration for character counter's highlight text color internal var highlightTextColor = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .normal) @@ -171,14 +171,34 @@ open class TextArea: EntryFieldBase { .pinLeading() .pinTrailingLessThanOrEqualTo(nil, 0, .defaultHigh) .pinBottom(0, .defaultHigh) + textView.isScrollEnabled = true textView.autocorrectionType = .no + + //events + textView + .publisher(for: .editingChanged) + .sink { [weak self] control in + self?.textViewDidChange(control) + }.store(in: &subscribers) + + textView + .publisher(for: .editingDidBegin) + .sink { [weak self] _ in + self?.setNeedsUpdate() + }.store(in: &subscribers) + + textView + .publisher(for: .editingDidEnd) + .sink { [weak self] _ in + self?.validate() + }.store(in: &subscribers) + 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) borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .focused) - textView.delegate = self characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() bottomContainerStackView.spacing = VDSLayout.space2X } @@ -215,12 +235,12 @@ open class TextArea: EntryFieldBase { widthConstraint?.isActive = false minWidthConstraint?.isActive = true } - + characterCounterLabel.text = getCharacterCounterText() statusIcon.color = iconColorConfiguration.getColor(self) - containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor - textView.isEditable = readOnly ? false : true + containerView.layer.borderColor = isReadOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor + textView.isEditable = isReadOnly ? false : true textView.backgroundColor = backgroundColorConfiguration.getColor(self) textView.tintColor = iconColorConfiguration.getColor(self) characterCounterLabel.surface = surface @@ -239,7 +259,7 @@ open class TextArea: EntryFieldBase { bottomStackView.addArrangedSubview(characterCounterLabel) return bottomStackView } - + /// Used to update any Accessibility properties. open override func updateAccessibility() { super.updateAccessibility() @@ -252,7 +272,7 @@ open class TextArea: EntryFieldBase { } open override var canBecomeFirstResponder: Bool { true } - + open override func resignFirstResponder() -> Bool { if textView.isFirstResponder { textView.resignFirstResponder() @@ -277,41 +297,7 @@ open class TextArea: EntryFieldBase { } } - open func highlightCharacterOverflow() { - let count = textView.text.count - guard let maxLength, maxLength > 0, count > maxLength else { - textView.textAttributes = nil - return - } - - var textAttributes = [any LabelAttributeModel]() - let location = maxLength - let length = count - maxLength - textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightBackgroundColor.getColor(self), isForegroundColor: false)) - textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightTextColor.getColor(self), isForegroundColor: true)) - - textView.textAttributes = textAttributes - } - - //-------------------------------------------------- - // MARK: - Validation - //-------------------------------------------------- - var countRule = CharacterCountRule() -} - -extension TextArea: UITextViewDelegate { - public func textViewDidBeginEditing(_ textView: UITextView) { - setNeedsUpdate() - } - - public func textViewDidEndEditing(_ textView: UITextView) { - setNeedsUpdate() - } - - //-------------------------------------------------- - // MARK: - UITextViewDelegate - //-------------------------------------------------- - public func textViewDidChange(_ textView: UITextView) { + func textViewDidChange(_ textView: UITextView) { //dynamic textView Height sizing based on Figma //if you want it to work "as-is" delete this code @@ -351,4 +337,25 @@ extension TextArea: UITextViewDelegate { } validate() } + + private func highlightCharacterOverflow() { + let count = textView.text.count + guard let maxLength, maxLength > 0, count > maxLength else { + textView.textAttributes = nil + return + } + + var textAttributes = [any LabelAttributeModel]() + let location = maxLength + let length = count - maxLength + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightBackgroundColor.getColor(self), isForegroundColor: false)) + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightTextColor.getColor(self), isForegroundColor: true)) + + textView.textAttributes = textAttributes + } + + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + var countRule = CharacterCountRule() }