From 64f0b570c48ef08be8373e02b1f4693b5c4f9f57 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 08:09:47 -0500 Subject: [PATCH] Refactored out checkbox and renamed to checkboxitem Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 12 +- VDS/Components/Checkbox/Checkbox.swift | 289 +------------------ VDS/Components/Checkbox/CheckboxGroup.swift | 10 +- VDS/Components/Checkbox/CheckboxItem.swift | 297 ++++++++++++++++++++ 4 files changed, 317 insertions(+), 291 deletions(-) create mode 100644 VDS/Components/Checkbox/CheckboxItem.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 8df5a950..c091ed02 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -96,6 +96,7 @@ EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; }; EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; }; EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFEB632A26473700C4C106 /* NSAttributedString.swift */; }; + EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */; }; EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; }; EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; }; EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; }; @@ -105,7 +106,7 @@ EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; }; EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; }; - EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* Checkbox.swift */; }; + EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* CheckboxItem.swift */; }; EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; }; EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09F289AB7EC00B287F5 /* View.swift */; }; EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0A1289AFB3900B287F5 /* Errorable.swift */; }; @@ -224,6 +225,7 @@ EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = ""; }; EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = ""; }; + EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = ""; }; EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = ""; }; EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = ""; }; @@ -232,7 +234,7 @@ EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = ""; }; EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = ""; }; - EAF7F0932899861000B287F5 /* Checkbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; + EAF7F0932899861000B287F5 /* CheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxItem.swift; sourceTree = ""; }; EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = ""; }; EAF7F09F289AB7EC00B287F5 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; EAF7F0A1289AFB3900B287F5 /* Errorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errorable.swift; sourceTree = ""; }; @@ -679,7 +681,8 @@ EAF7F092289985E200B287F5 /* Checkbox */ = { isa = PBXGroup; children = ( - EAF7F0932899861000B287F5 /* Checkbox.swift */, + EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */, + EAF7F0932899861000B287F5 /* CheckboxItem.swift */, EA89200528B526D6006B9984 /* CheckboxGroup.swift */, ); path = Checkbox; @@ -861,7 +864,7 @@ EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */, EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */, - EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */, + EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */, EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, EA985BEA29689B6D00F2FF2E /* TileletSubTitleModel.swift in Sources */, @@ -894,6 +897,7 @@ EA5E3058295105A40082B959 /* Tilelet.swift in Sources */, EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */, EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, + EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */, EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index fd08007a..fefe1787 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -2,7 +2,7 @@ // Checkbox.swift // VDS // -// Created by Matt Bruce on 7/22/22. +// Created by Matt Bruce on 6/5/23. // import Foundation @@ -11,285 +11,6 @@ import Combine import VDSColorTokens import VDSFormControlsTokens -/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``. -@objc(VDSCheckboxBase) -open class Checkbox: Control, Errorable, Changeable { - - //-------------------------------------------------- - // MARK: - Initializers - //-------------------------------------------------- - required public init() { - super.init(frame: .zero) - } - - public override init(frame: CGRect) { - super.init(frame: .zero) - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - } - - //-------------------------------------------------- - // MARK: - Private Properties - //-------------------------------------------------- - private var shouldShowError: Bool { - guard showError && !disabled && errorText?.isEmpty == false else { return false } - return true - } - - private var shouldShowLabels: Bool { - guard labelText?.isEmpty == false || childText?.isEmpty == false || labelAttributedText?.string.isEmpty == false || childAttributedText?.string.isEmpty == false else { return false } - return true - } - - private var mainStackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .top - $0.axis = .vertical - } - - private var selectorStackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .top - $0.axis = .horizontal - } - - private var selectorLabelStackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.axis = .vertical - } - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - public var onChangeSubscriber: AnyCancellable? { - willSet { - if let onChangeSubscriber { - onChangeSubscriber.cancel() - } - } - } - - open var label = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - $0.textPosition = .left - $0.textStyle = .boldBodyLarge - } - - open var childLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - $0.textPosition = .left - $0.textStyle = .bodyLarge - } - - open var errorLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - $0.textPosition = .left - $0.textStyle = .bodyMedium - } - - open var selectorView = CheckboxView() - - open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} - - open override var isSelected: Bool { didSet { setNeedsUpdate() }} - - open var labelText: String? { didSet { setNeedsUpdate() }} - - open var labelTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} - - open var labelAttributedText: NSAttributedString? { - didSet { - label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true) - label.attributedText = labelAttributedText - setNeedsUpdate() - } - } - - open var childText: String? { didSet { setNeedsUpdate() }} - - open var childTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} - - open var childAttributedText: NSAttributedString? { - didSet { - childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true) - childLabel.attributedText = childAttributedText - setNeedsUpdate() - } - } - - var _showError: Bool = false - open var showError: Bool { - get { _showError } - set { - if !isSelected && _showError != newValue { - _showError = newValue - setNeedsUpdate() - } - } - } - - open override var state: UIControl.State { - get { - var state = super.state - if showError { - state.insert(.error) - } - return state - } - } - - open var errorText: String? { didSet { setNeedsUpdate() }} - - open var inputId: String? { didSet { setNeedsUpdate() }} - - open var value: AnyHashable? { didSet { setNeedsUpdate() }} - - //-------------------------------------------------- - // MARK: - Constraints - //-------------------------------------------------- - - private var selectorHeightConstraint: NSLayoutConstraint? - private var selectorWidthConstraint: NSLayoutConstraint? - - //functions - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - open override func initialSetup() { - super.initialSetup() - onClick = { control in - control.toggle() - } - } - - open override func setup() { - super.setup() - - isAccessibilityElement = true - accessibilityTraits = .button - addSubview(mainStackView) - mainStackView.isUserInteractionEnabled = false - - mainStackView.addArrangedSubview(selectorStackView) - mainStackView.addArrangedSubview(errorLabel) - selectorStackView.addArrangedSubview(selectorView) - selectorStackView.addArrangedSubview(selectorLabelStackView) - selectorLabelStackView.addArrangedSubview(label) - selectorLabelStackView.addArrangedSubview(childLabel) - mainStackView.pinToSuperView() - } - - func updateLabels() { - - //deal with labels - if shouldShowLabels { - //add the stackview to hold the 2 labels - //top label - if let labelText { - label.surface = surface - label.disabled = disabled - label.attributes = labelTextAttributes - label.text = labelText - label.isHidden = false - } else if labelAttributedText != nil { - label.isHidden = false - - } else { - label.isHidden = true - } - - //bottom label - if let childText { - childLabel.text = childText - childLabel.surface = surface - childLabel.disabled = disabled - childLabel.attributes = childTextAttributes - childLabel.isHidden = false - - } else if childAttributedText != nil { - childLabel.isHidden = false - - } else { - childLabel.isHidden = true - } - selectorStackView.spacing = 12 - selectorLabelStackView.spacing = 4 - selectorLabelStackView.isHidden = false - - } else { - selectorStackView.spacing = 0 - selectorLabelStackView.spacing = 0 - selectorLabelStackView.isHidden = true - } - - //either add/remove the error from the main stack - if let errorText, shouldShowError { - errorLabel.text = errorText - errorLabel.surface = surface - errorLabel.disabled = disabled - mainStackView.spacing = 8 - errorLabel.isHidden = false - } else { - mainStackView.spacing = 0 - errorLabel.isHidden = true - } - } - - open override func reset() { - super.reset() - shouldUpdateView = false - label.reset() - childLabel.reset() - errorLabel.reset() - - label.textStyle = .boldBodyLarge - childLabel.textStyle = .bodyLarge - errorLabel.textStyle = .bodyMedium - - labelText = nil - labelTextAttributes = nil - labelAttributedText = nil - childText = nil - childTextAttributes = nil - childAttributedText = nil - showError = false - errorText = nil - inputId = nil - value = nil - isSelected = false - - shouldUpdateView = true - setNeedsUpdate() - } - - /// This will checkbox the state of the Selector and execute the actionBlock if provided. - open func toggle() { - //removed error - if showError && isSelected == false { - showError.toggle() - } - isSelected.toggle() - sendActions(for: .valueChanged) - } - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- - open override func updateView() { - updateLabels() - selectorView.isAnimated = isAnimated - selectorView.showError = showError - selectorView.isSelected = isSelected - updateAccessibilityLabel() - } - - open override func updateAccessibilityLabel() { - setAccessibilityLabel(for: [label, childLabel, errorLabel]) - } -} - public protocol SelectorControlable: Control, Changeable { var showError: Bool { get set } var size: CGSize { get set } @@ -298,7 +19,8 @@ public protocol SelectorControlable: Control, Changeable { var selectorColorConfig: ControlColorConfiguration { get set } } -open class CheckboxView: Control, SelectorControlable { +@objc(VDSCheckbox) +open class Checkbox: Control, SelectorControlable { public var onChangeSubscriber: AnyCancellable? open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} @@ -399,6 +121,9 @@ open class CheckboxView: Control, SelectorControlable { self.shapeLayer = nil } + layer.cornerRadius = 2.0 + layer.borderWidth = VDSFormControls.widthBorder + if shapeLayer == nil { let bounds = bounds let length = max(bounds.size.height, bounds.size.width) @@ -435,7 +160,7 @@ open class CheckboxView: Control, SelectorControlable { shapeLayer?.removeAllAnimations() - if isAnimated && !disabled { + if isAnimated && !disabled && !isHighlighted { let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) animateStrokeEnd.duration = 0.3 diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index b994a9cf..7c4817fc 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -9,18 +9,18 @@ import Foundation import UIKit @objc(VDSCheckboxGroup) -open class CheckboxGroup: SelectorGroupHandlerBase { +open class CheckboxGroup: SelectorGroupHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var selectedHandlers: [Checkbox]? { + public var selectedHandlers: [CheckboxItem]? { let selected = selectorViews.filter{ $0.isSelected == true } guard selected.count > 0 else { return nil } return selected } - public override var selectorViews: [Checkbox] { + public override var selectorViews: [CheckboxItem] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } @@ -39,7 +39,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { didSet { if let selectorModels { selectorViews = selectorModels.map { model in - return Checkbox().with { + return CheckboxItem().with { $0.disabled = model.disabled $0.surface = model.surface $0.inputId = model.inputId @@ -98,7 +98,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { mainStackView.pinToSuperView() } - public override func didSelect(_ selectedControl: Checkbox) { + public override func didSelect(_ selectedControl: CheckboxItem) { selectedControl.toggle() if selectedControl.isSelected, showError{ showError.toggle() diff --git a/VDS/Components/Checkbox/CheckboxItem.swift b/VDS/Components/Checkbox/CheckboxItem.swift new file mode 100644 index 00000000..368ccee6 --- /dev/null +++ b/VDS/Components/Checkbox/CheckboxItem.swift @@ -0,0 +1,297 @@ +// +// Checkbox.swift +// VDS +// +// Created by Matt Bruce on 7/22/22. +// + +import Foundation +import UIKit +import Combine +import VDSColorTokens +import VDSFormControlsTokens + +/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``. +@objc(VDSCheckboxBase) +open class CheckboxItem: Control, Errorable, Changeable { + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var shouldShowError: Bool { + guard showError && !disabled && errorText?.isEmpty == false else { return false } + return true + } + + private var shouldShowLabels: Bool { + guard labelText?.isEmpty == false || childText?.isEmpty == false || labelAttributedText?.string.isEmpty == false || childAttributedText?.string.isEmpty == false else { return false } + return true + } + + private var mainStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .top + $0.axis = .vertical + } + + private var selectorStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .top + $0.axis = .horizontal + } + + private var selectorLabelStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .vertical + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + public var onChangeSubscriber: AnyCancellable? { + willSet { + if let onChangeSubscriber { + onChangeSubscriber.cancel() + } + } + } + + open var label = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textPosition = .left + $0.textStyle = .boldBodyLarge + } + + open var childLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textPosition = .left + $0.textStyle = .bodyLarge + } + + open var errorLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textPosition = .left + $0.textStyle = .bodyMedium + } + + open var selectorView = Checkbox() + + open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} + + open override var isSelected: Bool { didSet { setNeedsUpdate() }} + + open var labelText: String? { didSet { setNeedsUpdate() }} + + open var labelTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} + + open var labelAttributedText: NSAttributedString? { + didSet { + label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true) + label.attributedText = labelAttributedText + setNeedsUpdate() + } + } + + open var childText: String? { didSet { setNeedsUpdate() }} + + open var childTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} + + open var childAttributedText: NSAttributedString? { + didSet { + childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true) + childLabel.attributedText = childAttributedText + setNeedsUpdate() + } + } + + var _showError: Bool = false + open var showError: Bool { + get { _showError } + set { + if !isSelected && _showError != newValue { + _showError = newValue + setNeedsUpdate() + } + } + } + + open override var state: UIControl.State { + get { + var state = super.state + if showError { + state.insert(.error) + } + return state + } + } + + open override var isHighlighted: Bool { + didSet { + selectorView.isHighlighted = isHighlighted + } + } + + open var errorText: String? { didSet { setNeedsUpdate() }} + + open var inputId: String? { didSet { setNeedsUpdate() }} + + open var value: AnyHashable? { didSet { setNeedsUpdate() }} + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + private var selectorHeightConstraint: NSLayoutConstraint? + private var selectorWidthConstraint: NSLayoutConstraint? + + //functions + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + + open override func setup() { + super.setup() + + isAccessibilityElement = true + accessibilityTraits = .button + addSubview(mainStackView) + mainStackView.isUserInteractionEnabled = false + + mainStackView.addArrangedSubview(selectorStackView) + mainStackView.addArrangedSubview(errorLabel) + selectorStackView.addArrangedSubview(selectorView) + selectorStackView.addArrangedSubview(selectorLabelStackView) + selectorLabelStackView.addArrangedSubview(label) + selectorLabelStackView.addArrangedSubview(childLabel) + mainStackView.pinToSuperView() + } + + func updateLabels() { + + //deal with labels + if shouldShowLabels { + //add the stackview to hold the 2 labels + //top label + if let labelText { + label.surface = surface + label.disabled = disabled + label.attributes = labelTextAttributes + label.text = labelText + label.isHidden = false + } else if labelAttributedText != nil { + label.isHidden = false + + } else { + label.isHidden = true + } + + //bottom label + if let childText { + childLabel.text = childText + childLabel.surface = surface + childLabel.disabled = disabled + childLabel.attributes = childTextAttributes + childLabel.isHidden = false + + } else if childAttributedText != nil { + childLabel.isHidden = false + + } else { + childLabel.isHidden = true + } + selectorStackView.spacing = 12 + selectorLabelStackView.spacing = 4 + selectorLabelStackView.isHidden = false + + } else { + selectorStackView.spacing = 0 + selectorLabelStackView.spacing = 0 + selectorLabelStackView.isHidden = true + } + + //either add/remove the error from the main stack + if let errorText, shouldShowError { + errorLabel.text = errorText + errorLabel.surface = surface + errorLabel.disabled = disabled + mainStackView.spacing = 8 + errorLabel.isHidden = false + } else { + mainStackView.spacing = 0 + errorLabel.isHidden = true + } + } + + open override func reset() { + super.reset() + shouldUpdateView = false + label.reset() + childLabel.reset() + errorLabel.reset() + + label.textStyle = .boldBodyLarge + childLabel.textStyle = .bodyLarge + errorLabel.textStyle = .bodyMedium + + labelText = nil + labelTextAttributes = nil + labelAttributedText = nil + childText = nil + childTextAttributes = nil + childAttributedText = nil + showError = false + errorText = nil + inputId = nil + value = nil + isSelected = false + + shouldUpdateView = true + setNeedsUpdate() + } + + /// This will checkbox the state of the Selector and execute the actionBlock if provided. + open func toggle() { + //removed error + if showError && isSelected == false { + showError.toggle() + } + isSelected.toggle() + sendActions(for: .valueChanged) + } + + //-------------------------------------------------- + // MARK: - State + //-------------------------------------------------- + open override func updateView() { + updateLabels() + selectorView.isAnimated = isAnimated + selectorView.showError = showError + selectorView.isSelected = isSelected + updateAccessibilityLabel() + } + + open override func updateAccessibilityLabel() { + setAccessibilityLabel(for: [label, childLabel, errorLabel]) + } +}