initial fix
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
a4d9fd0ccc
commit
522624b403
@ -111,16 +111,12 @@ open class DropdownSelect: EntryFieldBase {
|
||||
$0.font = TextStyle.bodyLarge.font
|
||||
}
|
||||
|
||||
/// Determines the placement of the helper text.
|
||||
open var helperTextPlacement: HelperTextPlacement = .bottom { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var optionsPicker = UIPickerView()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var inlineWidthConstraint: NSLayoutConstraint?
|
||||
internal var titleLabelWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
@ -133,13 +129,8 @@ open class DropdownSelect: EntryFieldBase {
|
||||
|
||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
widthConstraint?.activate()
|
||||
super.setup()
|
||||
|
||||
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
titleLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||
titleLabelWidthConstraint = titleLabel.width(constant: 0)
|
||||
|
||||
fieldStackView.isAccessibilityElement = true
|
||||
fieldStackView.accessibilityLabel = "Dropdown Select"
|
||||
inlineDisplayLabel.isAccessibilityElement = true
|
||||
@ -285,28 +276,6 @@ open class DropdownSelect: EntryFieldBase {
|
||||
statusIcon.color = iconColorConfiguration.getColor(self)
|
||||
}
|
||||
|
||||
open override func updateHelperLabel(){
|
||||
//remove first
|
||||
secondaryStackView.removeFromSuperview()
|
||||
helperLabel.removeFromSuperview()
|
||||
|
||||
super.updateHelperLabel()
|
||||
|
||||
//set the helper label position
|
||||
if helperText != nil {
|
||||
if helperTextPlacement == .right {
|
||||
horizontalStackView.addArrangedSubview(secondaryStackView)
|
||||
horizontalStackView.addArrangedSubview(helperLabel)
|
||||
primaryStackView.addArrangedSubview(horizontalStackView)
|
||||
} else {
|
||||
bottomContainerStackView.addArrangedSubview(helperLabel)
|
||||
primaryStackView.addArrangedSubview(secondaryStackView)
|
||||
}
|
||||
} else {
|
||||
primaryStackView.addArrangedSubview(secondaryStackView)
|
||||
}
|
||||
}
|
||||
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
let selectedOption = selectedOptionLabel.text ?? ""
|
||||
@ -343,13 +312,7 @@ open class DropdownSelect: EntryFieldBase {
|
||||
setNeedsUpdate()
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: fieldStackView)
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
titleLabelWidthConstraint?.constant = containerView.frame.width
|
||||
titleLabelWidthConstraint?.isActive = helperTextPlacement == .right
|
||||
}
|
||||
|
||||
|
||||
open override var canBecomeFirstResponder: Bool {
|
||||
return dropdownField.canBecomeFirstResponder
|
||||
}
|
||||
|
||||
@ -36,38 +36,41 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
public enum HelperTextPlacement: String, CaseIterable {
|
||||
case bottom, right
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
internal var primaryStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
$0.distribution = .fill
|
||||
$0.alignment = .leading
|
||||
}
|
||||
}()
|
||||
|
||||
/// This is the veritcal stack view that has 2 rows, the containerView and the return view
|
||||
/// of the getBottomContainer() method, by default returns the bottomContainerStackView.
|
||||
internal let secondaryStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
internal let mainStackView = UIStackView().with {
|
||||
$0.axis = .vertical
|
||||
$0.distribution = .fill
|
||||
$0.alignment = .fill
|
||||
$0.spacing = 8
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
/// This is the view that will be wrapped with the border for userInteraction.
|
||||
/// The only subview of this view is the fieldStackView
|
||||
internal var containerView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
internal let contentStackView = UIStackView().with {
|
||||
$0.axis = .vertical
|
||||
$0.alignment = .fill
|
||||
$0.distribution = .fill
|
||||
$0.spacing = 8
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
/// only used for helperTextPosition == .right
|
||||
internal let row1StackView = UIStackView().with {
|
||||
$0.axis = .horizontal
|
||||
$0.spacing = 8
|
||||
$0.alignment = .top
|
||||
$0.distribution = .fillEqually
|
||||
}
|
||||
|
||||
/// only used for helperTextPosition == .right
|
||||
internal let row2StackView = UIStackView().with {
|
||||
$0.axis = .horizontal
|
||||
$0.spacing = 8
|
||||
$0.alignment = .top
|
||||
$0.distribution = .fillEqually
|
||||
}
|
||||
|
||||
/// This is a horizontal Stack View that is placed inside the containterView (bordered view)
|
||||
/// The first arrangedView will be the view from getFieldContainer()
|
||||
/// The second view is the statusIcon.
|
||||
internal var fieldStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -86,9 +89,18 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
$0.spacing = VDSLayout.space2X
|
||||
}
|
||||
}()
|
||||
|
||||
/// This is the view that will be wrapped with the border for userInteraction.
|
||||
/// The only subview of this view is the fieldStackView
|
||||
internal var containerView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
|
||||
/// This is set by a local method.
|
||||
internal var bottomContainerView: UIView!
|
||||
|
||||
open var rules = [AnyRule<String>]()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
//--------------------------------------------------
|
||||
@ -136,7 +148,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
open var titleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
@ -199,36 +211,34 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
open var isRequired: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var isReadOnly: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var heightConstraint: NSLayoutConstraint?
|
||||
internal var widthConstraint: NSLayoutConstraint?
|
||||
|
||||
|
||||
open var helperTextPlacement: HelperTextPlacement = .bottom {
|
||||
didSet {
|
||||
updateHelperTextPosition()
|
||||
}
|
||||
}
|
||||
|
||||
open var rules = [AnyRule<String>]()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
isAccessibilityElement = false
|
||||
addSubview(primaryStackView)
|
||||
|
||||
//create the wrapping view
|
||||
heightConstraint = containerView.heightGreaterThanEqualTo(constant: containerSize.height)
|
||||
widthConstraint = containerView.width(constant: frame.size.width)
|
||||
|
||||
secondaryStackView.addArrangedSubview(containerView)
|
||||
secondaryStackView.setCustomSpacing(8, after: containerView)
|
||||
// Add mainStackView to the view
|
||||
addSubview(mainStackView)
|
||||
|
||||
mainStackView.pinToSuperView()
|
||||
|
||||
//add ContainerStackView
|
||||
//this is the horizontal stack that contains
|
||||
//the left, InputContainer, Icons, Buttons
|
||||
//InputContainer, Icons, Buttons
|
||||
containerView.addSubview(fieldStackView)
|
||||
fieldStackView.pinToSuperView(.uniform(VDSLayout.space3X))
|
||||
|
||||
|
||||
let fieldContainerView = getFieldContainer()
|
||||
fieldContainerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
@ -239,29 +249,33 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
|
||||
//get the container this is what show helper text, error text
|
||||
//can include other for character count, max length
|
||||
let bottomContainer = getBottomContainer()
|
||||
bottomContainerView = getBottomContainer()
|
||||
|
||||
//this is the vertical stack that contains error text, helper text
|
||||
bottomContainerStackView.addArrangedSubview(errorLabel)
|
||||
bottomContainerStackView.addArrangedSubview(helperLabel)
|
||||
|
||||
primaryStackView.addArrangedSubview(titleLabel)
|
||||
primaryStackView.addArrangedSubview(secondaryStackView)
|
||||
secondaryStackView.addArrangedSubview(bottomContainer)
|
||||
|
||||
primaryStackView.setCustomSpacing(4, after: titleLabel)
|
||||
|
||||
primaryStackView
|
||||
.pinTop()
|
||||
.pinLeading()
|
||||
.pinTrailing(0, .defaultHigh)
|
||||
.pinBottom(0, .defaultHigh)
|
||||
|
||||
titleLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable()
|
||||
errorLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable()
|
||||
helperLabel.textColorConfiguration = secondaryColorConfiguration.eraseToAnyColorable()
|
||||
// Add arranged subviews to textFieldStackView
|
||||
contentStackView.addArrangedSubview(containerView)
|
||||
contentStackView.addArrangedSubview(bottomContainerView)
|
||||
|
||||
// Add arranged subviews to mainStackView
|
||||
mainStackView.addArrangedSubview(titleLabel)
|
||||
mainStackView.addArrangedSubview(contentStackView)
|
||||
|
||||
// Initial position of the helper label
|
||||
updateHelperTextPosition()
|
||||
}
|
||||
|
||||
|
||||
/// Updates the UI
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
updateContainerView()
|
||||
updateTitleLabel()
|
||||
updateErrorLabel()
|
||||
updateHelperLabel()
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
@ -284,48 +298,12 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
defaultValue = nil
|
||||
isRequired = false
|
||||
isReadOnly = false
|
||||
onChange = nil
|
||||
onChange = nil
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
updateContainerView()
|
||||
updateTitleLabel()
|
||||
updateErrorLabel()
|
||||
updateHelperLabel()
|
||||
updateContainerWidth()
|
||||
}
|
||||
|
||||
open func validate(){
|
||||
updateRules()
|
||||
validator = FormFieldValidator<EntryFieldBase>(field: self, rules: rules)
|
||||
validator?.validate()
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
internal func updateContainerView() {
|
||||
containerView.backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||
containerView.layer.borderColor = isReadOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor
|
||||
containerView.layer.borderWidth = VDSFormControls.borderWidth
|
||||
containerView.layer.cornerRadius = VDSFormControls.borderRadius
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Methods
|
||||
//--------------------------------------------------
|
||||
open func updateContainerWidth() {
|
||||
if let width, width > minWidth && width < maxWidth {
|
||||
widthConstraint?.constant = width
|
||||
} else {
|
||||
widthConstraint?.constant = maxWidth >= minWidth ? maxWidth : minWidth
|
||||
}
|
||||
widthConstraint?.activate()
|
||||
}
|
||||
|
||||
/// Container for the area in which the user interacts.
|
||||
open func getFieldContainer() -> UIView {
|
||||
fatalError("Subclass must return the view that contains the field/view the user will interact with.")
|
||||
@ -335,22 +313,14 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
open func getBottomContainer() -> UIView {
|
||||
return bottomContainerStackView
|
||||
}
|
||||
|
||||
internal func updateRules() {
|
||||
rules.removeAll()
|
||||
if self.isRequired {
|
||||
let rule = RequiredRule()
|
||||
if let errorText, !errorText.isEmpty {
|
||||
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 validate(){
|
||||
updateRules()
|
||||
validator = FormFieldValidator<EntryFieldBase>(field: self, rules: rules)
|
||||
validator?.validate()
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
|
||||
open func updateTitleLabel() {
|
||||
|
||||
//update the local vars for the label since we no
|
||||
@ -380,7 +350,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
titleLabel.surface = surface
|
||||
titleLabel.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
|
||||
open func updateErrorLabel(){
|
||||
if showError, let errorText {
|
||||
errorLabel.text = errorText
|
||||
@ -416,4 +386,73 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
helperLabel.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
internal func updateRules() {
|
||||
rules.removeAll()
|
||||
if self.isRequired {
|
||||
let rule = RequiredRule()
|
||||
if let errorText, !errorText.isEmpty {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
internal func updateContainerView() {
|
||||
containerView.backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||
containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor
|
||||
containerView.layer.borderWidth = VDSFormControls.borderWidth
|
||||
containerView.layer.cornerRadius = VDSFormControls.borderRadius
|
||||
}
|
||||
|
||||
internal func updateHelperTextPosition() {
|
||||
|
||||
titleLabel.removeFromSuperview()
|
||||
helperLabel.removeFromSuperview()
|
||||
|
||||
contentStackView.removeFromSuperview()
|
||||
mainStackView.removeArrangedSubviews()
|
||||
|
||||
//rows for helper-right
|
||||
row1StackView.removeArrangedSubviews()
|
||||
row2StackView.removeArrangedSubviews()
|
||||
row1StackView.removeFromSuperview()
|
||||
row2StackView.removeFromSuperview()
|
||||
|
||||
switch helperTextPlacement {
|
||||
case .bottom:
|
||||
//add helper back into the contentView
|
||||
bottomContainerStackView.addArrangedSubview(helperLabel)
|
||||
mainStackView.addArrangedSubview(titleLabel)
|
||||
mainStackView.addArrangedSubview(contentStackView)
|
||||
|
||||
case .right:
|
||||
//first row
|
||||
row1StackView.addArrangedSubview(titleLabel)
|
||||
//add spacer
|
||||
row1StackView.addArrangedSubview(UIView())
|
||||
|
||||
//second row
|
||||
row2StackView.addArrangedSubview(contentStackView)
|
||||
//add under spacer
|
||||
row2StackView.addArrangedSubview(helperLabel)
|
||||
|
||||
//add 2 rows to vertical stack to create the grid
|
||||
mainStackView.addArrangedSubview(row1StackView)
|
||||
mainStackView.addArrangedSubview(row2StackView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIStackView {
|
||||
public func removeArrangedSubviews() {
|
||||
arrangedSubviews.forEach { removeArrangedSubview($0) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,6 @@ open class InputField: EntryFieldBase {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
internal var titleLabelWidthConstraint: NSLayoutConstraint?
|
||||
internal override var minWidth: CGFloat { fieldType.handler().minWidth }
|
||||
internal override var maxWidth: CGFloat {
|
||||
let frameWidth = frame.size.width
|
||||
@ -172,25 +171,17 @@ open class InputField: EntryFieldBase {
|
||||
|
||||
/// If given, this will be shown if showSuccess if true.
|
||||
open var successText: String? { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Determines the placement of the helper text.
|
||||
open var helperTextPlacement: HelperTextPlacement = .bottom { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
titleLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||
titleLabelWidthConstraint = titleLabel.width(constant: 0)
|
||||
|
||||
super.setup()
|
||||
textField.heightAnchor.constraint(equalToConstant: 20).isActive = true
|
||||
textField.delegate = self
|
||||
primaryStackView.addArrangedSubview(successLabel)
|
||||
primaryStackView.setCustomSpacing(8, after: successLabel)
|
||||
mainStackView.addArrangedSubview(successLabel)
|
||||
mainStackView.setCustomSpacing(8, after: successLabel)
|
||||
|
||||
fieldStackView.addArrangedSubview(actionTextLink)
|
||||
|
||||
@ -262,27 +253,6 @@ open class InputField: EntryFieldBase {
|
||||
}
|
||||
|
||||
}
|
||||
open override func updateHelperLabel(){
|
||||
//remove first
|
||||
secondaryStackView.removeFromSuperview()
|
||||
helperLabel.removeFromSuperview()
|
||||
|
||||
super.updateHelperLabel()
|
||||
|
||||
//set the helper label position
|
||||
if helperText != nil {
|
||||
if helperTextPlacement == .right {
|
||||
horizontalStackView.addArrangedSubview(secondaryStackView)
|
||||
horizontalStackView.addArrangedSubview(helperLabel)
|
||||
primaryStackView.addArrangedSubview(horizontalStackView)
|
||||
} else {
|
||||
bottomContainerStackView.addArrangedSubview(helperLabel)
|
||||
primaryStackView.addArrangedSubview(secondaryStackView)
|
||||
}
|
||||
} else {
|
||||
primaryStackView.addArrangedSubview(secondaryStackView)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateRules() {
|
||||
super.updateRules()
|
||||
@ -318,12 +288,6 @@ open class InputField: EntryFieldBase {
|
||||
set { super.accessibilityElements = newValue }
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
titleLabelWidthConstraint?.constant = containerView.frame.width
|
||||
titleLabelWidthConstraint?.isActive = helperTextPlacement == .right
|
||||
}
|
||||
|
||||
open override var canBecomeFirstResponder: Bool {
|
||||
return textField.canBecomeFirstResponder
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user