From 276b3c327df5409bc6b74f07a80932768b24fd8c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 31 May 2023 14:08:32 -0500 Subject: [PATCH 01/18] refactor out checkboxview Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/Checkbox.swift | 133 +++++++++++++++++-------- 1 file changed, 91 insertions(+), 42 deletions(-) diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 630b97ce..fd08007a 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -89,10 +89,8 @@ open class Checkbox: Control, Errorable, Changeable { $0.textStyle = .bodyMedium } - open var selectorView = UIView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - + open var selectorView = CheckboxView() + open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} open override var isSelected: Bool { didSet { setNeedsUpdate() }} @@ -180,18 +178,7 @@ open class Checkbox: Control, Errorable, Changeable { selectorStackView.addArrangedSubview(selectorLabelStackView) selectorLabelStackView.addArrangedSubview(label) selectorLabelStackView.addArrangedSubview(childLabel) - - let selectorSize = getSelectorSize() - selectorHeightConstraint = selectorView.heightAnchor.constraint(equalToConstant: selectorSize.height) - selectorHeightConstraint?.isActive = true - - selectorWidthConstraint = selectorView.widthAnchor.constraint(equalToConstant: selectorSize.width) - selectorWidthConstraint?.isActive = true - - updateSelector() - mainStackView.pinToSuperView() - } func updateLabels() { @@ -292,66 +279,128 @@ open class Checkbox: Control, Errorable, Changeable { //-------------------------------------------------- open override func updateView() { updateLabels() - updateSelector() + 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 } + var backgroundColorConfig: ControlColorConfiguration { get set } + var borderColorConfig: ControlColorConfiguration { get set } + var selectorColorConfig: ControlColorConfiguration { get set } +} + +open class CheckboxView: Control, SelectorControlable { + public var onChangeSubscriber: AnyCancellable? + + open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} + + open var size = CGSize(width: 20, height: 20) { didSet { setNeedsUpdate() }} + + var _showError: Bool = false + open var showError: Bool { + get { _showError } + set { + if !isSelected && _showError != newValue { + _showError = newValue + setNeedsUpdate() + } + } + } - //-------------------------------------------------- - // MARK: - Configuration Properties - //-------------------------------------------------- - public let checkboxSize = CGSize(width: 20, height: 20) - - private var backgroundColorConfig = ControlColorConfiguration().with { + open override var state: UIControl.State { + get { + var state = super.state + if showError { + state.insert(.error) + } + return state + } + } + + open var backgroundColorConfig = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected,.highlighted]) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - } + }{ didSet { setNeedsUpdate() }} - private var borderColorConfig = ControlColorConfiguration().with { + open var borderColorConfig = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - } + }{ didSet { setNeedsUpdate() }} - private var checkColorConfig = ControlColorConfiguration().with { + open var selectorColorConfig = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .disabled]) $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .highlighted]) - } - + }{ didSet { setNeedsUpdate() }} + //-------------------------------------------------- - // MARK: - Checkbox View + // MARK: - Constraints //-------------------------------------------------- - /// Manages the appearance of the checkbox. + private var selectorHeightConstraint: NSLayoutConstraint? + private var selectorWidthConstraint: NSLayoutConstraint? + private var shapeLayer: CAShapeLayer? + + open override func setup() { + super.setup() + let layoutGuide = UILayoutGuide() + addLayoutGuide(layoutGuide) + + selectorHeightConstraint = layoutGuide.heightAnchor.constraint(equalToConstant: size.height) + selectorHeightConstraint?.isActive = true + + selectorWidthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: size.width) + selectorWidthConstraint?.isActive = true + + NSLayoutConstraint.activate([ + layoutGuide.topAnchor.constraint(equalTo: topAnchor), + layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), + layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), + layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) - open func getSelectorSize() -> CGSize { - return checkboxSize + layer.cornerRadius = 2.0 + layer.borderWidth = VDSFormControls.widthBorder + + } + open override func updateView() { + super.updateView() + + selectorHeightConstraint?.constant = size.height + selectorWidthConstraint?.constant = size.width + + setNeedsLayout() + layoutIfNeeded() } - open func updateSelector() { + open override func layoutSubviews() { + super.layoutSubviews() + //get the colors let backgroundColor = backgroundColorConfig.getColor(self) let borderColor = borderColorConfig.getColor(self) - let checkColor = checkColorConfig.getColor(self) + let checkColor = selectorColorConfig.getColor(self) if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() self.shapeLayer = nil } - selectorView.layer.cornerRadius = VDSFormControls.borderradius - selectorView.layer.borderWidth = VDSFormControls.widthBorder - if shapeLayer == nil { - let bounds = selectorView.bounds + let bounds = bounds let length = max(bounds.size.height, bounds.size.width) guard length > 0.0, shapeLayer == nil else { return } @@ -397,16 +446,16 @@ open class Checkbox: Control, Errorable, Changeable { self.shapeLayer?.add(animateStrokeEnd, forKey: "strokeEnd") UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: { - self.selectorView.backgroundColor = backgroundColor - self.selectorView.layer.borderColor = borderColor.cgColor + self.backgroundColor = backgroundColor + self.layer.borderColor = borderColor.cgColor }) } else { CATransaction.withDisabledAnimations { self.shapeLayer?.strokeEnd = isSelected ? 1 : 0 } - selectorView.backgroundColor = backgroundColor - selectorView.layer.borderColor = borderColor.cgColor + self.backgroundColor = backgroundColor + layer.borderColor = borderColor.cgColor } } } From 2e6d4943a21e6b3c29f61a55fa9c6aa7e24b47ce Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 31 May 2023 14:09:53 -0500 Subject: [PATCH 02/18] updated corner radius of checkbox view Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/Checkbox.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 630b97ce..897ccff9 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -347,7 +347,7 @@ open class Checkbox: Control, Errorable, Changeable { self.shapeLayer = nil } - selectorView.layer.cornerRadius = VDSFormControls.borderradius + selectorView.layer.cornerRadius = 2.0 selectorView.layer.borderWidth = VDSFormControls.widthBorder if shapeLayer == nil { From c9b667d4c58d031976f5c72f16b4e5b8ee420ff7 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Jun 2023 14:52:31 -0500 Subject: [PATCH 03/18] fixed issue with color Signed-off-by: Matt Bruce --- VDS/Classes/ColorConfiguration.swift | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/VDS/Classes/ColorConfiguration.swift b/VDS/Classes/ColorConfiguration.swift index 9d902a1d..e0b3a7c1 100644 --- a/VDS/Classes/ColorConfiguration.swift +++ b/VDS/Classes/ColorConfiguration.swift @@ -111,7 +111,6 @@ public class ControlColorConfiguration: KeyColorConfigurable { public typealias KeyType = UIControl.State public typealias ObjectType = Surfaceable & UIControl public var keyColors: [KeyColorConfiguration] = [] - private var lastKeyColor: KeyColorConfiguration? public required init() { } @@ -130,26 +129,11 @@ public class ControlColorConfiguration: KeyColorConfigurable { public func getColor(_ object: any ObjectType) -> UIColor { let state = object.state let surface = object.surface - - // find the exact match - if let keyColor = keyColors.first(where: {$0.key == state }) { - lastKeyColor = keyColor - return keyColor.surfaceConfig.getColor(surface) - } else if state.contains(.disabled), let keyColor = keyColors.first(where: {$0.key == .disabled }) { - lastKeyColor = keyColor + if let keyColor = keyColors.first(where: {$0.key.isSubset(of: state) }) { return keyColor.surfaceConfig.getColor(surface) - - } else if state.contains(.highlighted), let keyColor = keyColors.first(where: {$0.key == .highlighted }) { - lastKeyColor = keyColor - return keyColor.surfaceConfig.getColor(surface) - } else { - if let lastKeyColor { - return lastKeyColor.surfaceConfig.getColor(surface) - } else { - return .clear - } + return .clear } } } From 64f0b570c48ef08be8373e02b1f4693b5c4f9f57 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 08:09:47 -0500 Subject: [PATCH 04/18] 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]) + } +} From 8472a5ec3801c8b464963f6dd5f7976035e70154 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 10:42:19 -0500 Subject: [PATCH 05/18] added selector base controls for element and item Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 22 ++- VDS/Classes/SelectorBase.swift | 98 ++++++++++ VDS/Classes/SelectorItemBase.swift | 276 +++++++++++++++++++++++++++++ 3 files changed, 391 insertions(+), 5 deletions(-) create mode 100644 VDS/Classes/SelectorBase.swift create mode 100644 VDS/Classes/SelectorItemBase.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index c091ed02..26d8ae24 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; }; + EA1DA1CB2A2E36DC001C51D2 /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1DA1CA2A2E36DC001C51D2 /* SelectorBase.swift */; }; EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1F266128B945070033E859 /* RadioSwatch.swift */; }; EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1F266228B945070033E859 /* RadioSwatchGroup.swift */; }; EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; }; @@ -97,6 +98,8 @@ 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 */; }; + EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */; }; + EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A202A2E1DC000E47A9F /* SelectorItemBase.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 */; }; @@ -119,7 +122,7 @@ EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0B2289B1ADC00B287F5 /* ActionLabelAttribute.swift */; }; EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */; }; EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */; }; - EAF7F11728A1475A00B287F5 /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F11528A1475A00B287F5 /* RadioButton.swift */; }; + EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */; }; EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */; }; /* End PBXBuildFile section */ @@ -140,6 +143,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; + EA1DA1CA2A2E36DC001C51D2 /* SelectorBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; EA1F266128B945070033E859 /* RadioSwatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = ""; }; EA1F266228B945070033E859 /* RadioSwatchGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatchGroup.swift; sourceTree = ""; }; EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = ""; }; @@ -226,6 +230,8 @@ 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 = ""; }; + EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; + EAC71A202A2E1DC000E47A9F /* SelectorItemBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorItemBase.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 = ""; }; @@ -247,7 +253,7 @@ EAF7F0B2289B1ADC00B287F5 /* ActionLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionLabelAttribute.swift; sourceTree = ""; }; EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITapGestureRecognizer.swift; sourceTree = ""; }; EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConfiguration.swift; sourceTree = ""; }; - EAF7F11528A1475A00B287F5 /* RadioButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; + EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonItem.swift; sourceTree = ""; }; EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentLabelAttributeModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -466,8 +472,10 @@ EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */, EA3361B5288B2A410071C351 /* Control.swift */, EAF7F09F289AB7EC00B287F5 /* View.swift */, - EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */, EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */, + EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */, + EAC71A202A2E1DC000E47A9F /* SelectorItemBase.swift */, + EA1DA1CA2A2E36DC001C51D2 /* SelectorBase.swift */, ); path = Classes; sourceTree = ""; @@ -708,7 +716,8 @@ EAF7F11428A1470D00B287F5 /* RadioButton */ = { isa = PBXGroup; children = ( - EAF7F11528A1475A00B287F5 /* RadioButton.swift */, + EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */, + EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */, EAB1D29B28A5618900DAE764 /* RadioButtonGroup.swift */, ); path = RadioButton; @@ -857,9 +866,10 @@ EAC925842911C63100091998 /* Colorable.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, + EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, - EAF7F11728A1475A00B287F5 /* RadioButton.swift in Sources */, + EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */, EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */, EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */, @@ -926,9 +936,11 @@ EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */, EA3361BF288B2EA60071C351 /* Handlerable.swift in Sources */, EA3361A8288B23300071C351 /* UIColor.swift in Sources */, + EA1DA1CB2A2E36DC001C51D2 /* SelectorBase.swift in Sources */, EAC9257D29119B5400091998 /* TextLink.swift in Sources */, EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */, EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */, + EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */, EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */, 5FC35BE328D51405004EBEAC /* Button.swift in Sources */, ); diff --git a/VDS/Classes/SelectorBase.swift b/VDS/Classes/SelectorBase.swift new file mode 100644 index 00000000..315aab1f --- /dev/null +++ b/VDS/Classes/SelectorBase.swift @@ -0,0 +1,98 @@ +// +// SelectorBase.swift +// VDS +// +// Created by Matt Bruce on 6/5/23. +// + +import Foundation +import Combine +import VDSColorTokens +import VDSFormControlsTokens + +public protocol SelectorControlable: Control, Changeable { + var showError: Bool { get set } + var size: CGSize { get set } + var backgroundColorConfig: ControlColorConfiguration { get set } + var borderColorConfig: ControlColorConfiguration { get set } + var selectorColorConfig: ControlColorConfiguration { get set } +} + +open class SelectorBase: Control, SelectorControlable { + public var onChangeSubscriber: AnyCancellable? { + willSet { + if let onChangeSubscriber { + onChangeSubscriber.cancel() + } + } + } + + open var size = CGSize(width: 20, height: 20) { didSet { 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 backgroundColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + + open var borderColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + + open var selectorColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + private var selectorHeightConstraint: NSLayoutConstraint? + private var selectorWidthConstraint: NSLayoutConstraint? + + internal var shapeLayer: CAShapeLayer? + + open override func setup() { + super.setup() + let layoutGuide = UILayoutGuide() + addLayoutGuide(layoutGuide) + + selectorHeightConstraint = layoutGuide.heightAnchor.constraint(equalToConstant: size.height) + selectorHeightConstraint?.isActive = true + + selectorWidthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: size.width) + selectorWidthConstraint?.isActive = true + + NSLayoutConstraint.activate([ + layoutGuide.topAnchor.constraint(equalTo: topAnchor), + layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), + layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), + layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) + + layer.cornerRadius = 2.0 + layer.borderWidth = VDSFormControls.widthBorder + + } + open override func updateView() { + super.updateView() + + selectorHeightConstraint?.constant = size.height + selectorWidthConstraint?.constant = size.width + + setNeedsLayout() + layoutIfNeeded() + } + +} diff --git a/VDS/Classes/SelectorItemBase.swift b/VDS/Classes/SelectorItemBase.swift new file mode 100644 index 00000000..3982843a --- /dev/null +++ b/VDS/Classes/SelectorItemBase.swift @@ -0,0 +1,276 @@ +// +// SelectorItemBase.swift +// VDS +// +// Created by Matt Bruce on 6/5/23. +// + +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``. +open class SelectorItemBase: 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 + //-------------------------------------------------- + open 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 = Selector() + + 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() }} + + //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() {} + + //-------------------------------------------------- + // MARK: - State + //-------------------------------------------------- + open override func updateView() { + updateLabels() + selectorView.showError = showError + selectorView.isSelected = isSelected + selectorView.isHighlighted = isHighlighted + updateAccessibilityLabel() + } + + open override func updateAccessibilityLabel() { + setAccessibilityLabel(for: [label, childLabel, errorLabel]) + } +} From 42e6f9025c60eec270313914336c555b0c1b6332 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 10:42:42 -0500 Subject: [PATCH 06/18] refactored checkbox for new subclasses Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/Checkbox.swift | 106 ++------- VDS/Components/Checkbox/CheckboxItem.swift | 260 +-------------------- 2 files changed, 22 insertions(+), 344 deletions(-) diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index fefe1787..bb47479d 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -11,101 +11,29 @@ import Combine import VDSColorTokens import VDSFormControlsTokens -public protocol SelectorControlable: Control, Changeable { - var showError: Bool { get set } - var size: CGSize { get set } - var backgroundColorConfig: ControlColorConfiguration { get set } - var borderColorConfig: ControlColorConfiguration { get set } - var selectorColorConfig: ControlColorConfiguration { get set } -} - @objc(VDSCheckbox) -open class Checkbox: Control, SelectorControlable { - public var onChangeSubscriber: AnyCancellable? +open class Checkbox: SelectorBase { open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} - open var size = CGSize(width: 20, height: 20) { didSet { 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 backgroundColorConfig = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected,.highlighted]) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) - $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - }{ didSet { setNeedsUpdate() }} - - open var borderColorConfig = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - }{ didSet { setNeedsUpdate() }} - - open var selectorColorConfig = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) - $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .disabled]) - $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .highlighted]) - }{ didSet { setNeedsUpdate() }} - - //-------------------------------------------------- - // MARK: - Constraints - //-------------------------------------------------- - private var selectorHeightConstraint: NSLayoutConstraint? - private var selectorWidthConstraint: NSLayoutConstraint? - - private var shapeLayer: CAShapeLayer? - open override func setup() { super.setup() - let layoutGuide = UILayoutGuide() - addLayoutGuide(layoutGuide) - selectorHeightConstraint = layoutGuide.heightAnchor.constraint(equalToConstant: size.height) - selectorHeightConstraint?.isActive = true - - selectorWidthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: size.width) - selectorWidthConstraint?.isActive = true - - NSLayoutConstraint.activate([ - layoutGuide.topAnchor.constraint(equalTo: topAnchor), - layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) - - layer.cornerRadius = 2.0 - layer.borderWidth = VDSFormControls.widthBorder - - } - open override func updateView() { - super.updateView() - - selectorHeightConstraint?.constant = size.height - selectorWidthConstraint?.constant = size.width + backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected,.highlighted]) + backgroundColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - setNeedsLayout() - layoutIfNeeded() + borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) + + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .disabled]) + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .highlighted]) + } open override func layoutSubviews() { @@ -114,7 +42,7 @@ open class Checkbox: Control, SelectorControlable { //get the colors let backgroundColor = backgroundColorConfig.getColor(self) let borderColor = borderColorConfig.getColor(self) - let checkColor = selectorColorConfig.getColor(self) + let selectorColor = selectorColorConfig.getColor(self) if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() @@ -148,7 +76,7 @@ open class Checkbox: Control, SelectorControlable { self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = checkColor.cgColor + shapeLayer.strokeColor = selectorColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.path = bezierPath.cgPath shapeLayer.lineJoin = .miter diff --git a/VDS/Components/Checkbox/CheckboxItem.swift b/VDS/Components/Checkbox/CheckboxItem.swift index 368ccee6..d580d87a 100644 --- a/VDS/Components/Checkbox/CheckboxItem.swift +++ b/VDS/Components/Checkbox/CheckboxItem.swift @@ -7,13 +7,10 @@ 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 { +@objc(VDSCheckboxItem) +open class CheckboxItem: SelectorItemBase { //-------------------------------------------------- // MARK: - Initializers @@ -31,247 +28,10 @@ open class CheckboxItem: Control, Errorable, Changeable { } //-------------------------------------------------- - // MARK: - Private Properties + // MARK: - Overrides //-------------------------------------------------- - 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() { + open override func toggle() { //removed error if showError && isSelected == false { showError.toggle() @@ -280,18 +40,8 @@ open class CheckboxItem: Control, Errorable, Changeable { 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]) + super.updateView() } } From 17fe50223c6195eb8d4a06b929dc81aa391ed2cb Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 10:43:02 -0500 Subject: [PATCH 07/18] refactored radiobutton for new subclasses Signed-off-by: Matt Bruce --- VDS/Components/RadioButton/RadioButton.swift | 360 ++---------------- .../RadioButton/RadioButtonGroup.swift | 10 +- .../RadioButton/RadioButtonItem.swift | 44 +++ 3 files changed, 82 insertions(+), 332 deletions(-) create mode 100644 VDS/Components/RadioButton/RadioButtonItem.swift diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index 705af90e..6c794f83 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -2,7 +2,7 @@ // RadioButton.swift // VDS // -// Created by Matt Bruce on 7/22/22. +// Created by Matt Bruce on 6/5/23. // import Foundation @@ -12,352 +12,58 @@ import VDSColorTokens import VDSFormControlsTokens @objc(VDSRadioButton) -open class RadioButton: Control, Errorable, Changeable { +open class RadioButton: SelectorBase { - //-------------------------------------------------- - // MARK: - Initializers - //-------------------------------------------------- - required public init() { - super.init(frame: .zero) - } + open var selectedSize = CGSize(width: 10, height: 10) { didSet { setNeedsUpdate() }} - 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 - } - - public var selectorView = UIView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - - 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() - } - } - - open var showError: Bool = false { didSet { 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 + backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled]) + borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) + + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + selectorColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + + } + + open override func layoutSubviews() { + super.layoutSubviews() + + //get the colors + let backgroundColor = backgroundColorConfig.getColor(self) + let borderColor = borderColorConfig.getColor(self) + let selectorColor = selectorColorConfig.getColor(self) - mainStackView.addArrangedSubview(selectorStackView) - mainStackView.addArrangedSubview(errorLabel) - selectorStackView.addArrangedSubview(selectorView) - selectorStackView.addArrangedSubview(selectorLabelStackView) - selectorLabelStackView.addArrangedSubview(label) - selectorLabelStackView.addArrangedSubview(childLabel) - - let selectorSize = getSelectorSize() - selectorHeightConstraint = selectorView.heightAnchor.constraint(equalToConstant: selectorSize.height) - selectorHeightConstraint?.isActive = true - - selectorWidthConstraint = selectorView.widthAnchor.constraint(equalToConstant: selectorSize.width) - selectorWidthConstraint?.isActive = true - - updateSelector() - - mainStackView.pinToSuperView() - - } - - func updateLabels() { - - //deal with labels - if shouldShowLabels { - //add the stackview to hold the 2 labels - //top label - if let labelText { - label.text = labelText - label.surface = surface - label.disabled = disabled - label.attributes = labelTextAttributes - 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() { - guard !isSelected else { return } - - //removed error - if showError && isSelected == false { - showError.toggle() - } - isSelected.toggle() - sendActions(for: .valueChanged) - } - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- - open override func updateView() { - updateLabels() - updateSelector() - updateAccessibilityLabel() - } - - open override func updateAccessibilityLabel() { - setAccessibilityLabel(for: [label, childLabel]) - } - - //-------------------------------------------------- - // MARK: - Configuration Properties - //-------------------------------------------------- - public let radioButtonSize = CGSize(width: 20, height: 20) - public let radioButtonSelectedSize = CGSize(width: 10, height: 10) - - private var backgroundColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - } - - private var borderColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled]) - $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - } - - private var checkColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) - } - - //-------------------------------------------------- - // MARK: - RadioButton View - //-------------------------------------------------- - /// Manages the appearance of the radioButton. - private var shapeLayer: CAShapeLayer? - open func getSelectorSize() -> CGSize { - radioButtonSize - } - - open func updateSelector() { - if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() self.shapeLayer = nil } - let bounds = radioButtonSize - let length = max(bounds.height, bounds.width) - guard length > 0.0, shapeLayer == nil else { return } + let bounds = bounds - //get the colors - let backgroundColor = backgroundColorConfiguration.getColor(self) - let borderColor = borderColorConfiguration.getColor(self) - let radioSelectedColor = checkColorConfiguration.getColor(self) - - selectorView.backgroundColor = backgroundColor - selectorView.layer.borderColor = borderColor.cgColor - selectorView.layer.cornerRadius = bounds.width * 0.5 - selectorView.layer.borderWidth = VDSFormControls.widthBorder + self.backgroundColor = backgroundColor + layer.borderColor = borderColor.cgColor + layer.cornerRadius = bounds.width * 0.5 + layer.borderWidth = VDSFormControls.widthBorder if shapeLayer == nil { - let selectedBounds = radioButtonSelectedSize + let selectedBounds = selectedSize let bezierPath = UIBezierPath(ovalIn: CGRect(x: (bounds.width - selectedBounds.width) / 2, y: (bounds.height - selectedBounds.height) / 2, - width: radioButtonSelectedSize.width, - height: radioButtonSelectedSize.height)) + width: selectedSize.width, + height: selectedSize.height)) let shapeLayer = CAShapeLayer() self.shapeLayer = shapeLayer - shapeLayer.frame = selectorView.bounds + shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.fillColor = radioSelectedColor.cgColor + shapeLayer.fillColor = selectorColor.cgColor shapeLayer.path = bezierPath.cgPath } } } - diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index ffdfdde3..992d76a5 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -9,12 +9,12 @@ import Foundation import UIKit @objc(VDSRadioButtonGroup) -open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { +open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var selectorViews: [RadioButton] { + public override var selectorViews: [RadioButtonItem] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } @@ -33,7 +33,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { didSet { if let selectorModels { selectorViews = selectorModels.map { model in - return RadioButton().with { + return RadioButtonItem().with { $0.disabled = model.disabled $0.surface = model.surface $0.inputId = model.inputId @@ -93,7 +93,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { mainStackView.pinToSuperView() } - public override func didSelect(_ selectedControl: RadioButton) { + public override func didSelect(_ selectedControl: RadioButtonItem) { if let selectedHandler { updateToggle(selectedHandler) } @@ -104,7 +104,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { valueChanged() } - private func updateToggle(_ radioButton: RadioButton) { + private func updateToggle(_ radioButton: RadioButtonItem) { if radioButton.showError && radioButton.isSelected == false { radioButton.showError.toggle() } diff --git a/VDS/Components/RadioButton/RadioButtonItem.swift b/VDS/Components/RadioButton/RadioButtonItem.swift new file mode 100644 index 00000000..14ed50fb --- /dev/null +++ b/VDS/Components/RadioButton/RadioButtonItem.swift @@ -0,0 +1,44 @@ +// +// RadioButton.swift +// VDS +// +// Created by Matt Bruce on 7/22/22. +// + +import Foundation +import UIKit + +@objc(VDSRadioButtonItem) +open class RadioButtonItem: SelectorItemBase { + + //-------------------------------------------------- + // 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: - Overrides + //-------------------------------------------------- + /// This will checkbox the state of the Selector and execute the actionBlock if provided. + open override func toggle() { + guard !isSelected else { return } + + //removed error + if showError && isSelected == false { + showError.toggle() + } + isSelected.toggle() + sendActions(for: .valueChanged) + } +} + From a2c3c94ef1b6a3c971052b483b0727f980eb4af5 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 10:57:56 -0500 Subject: [PATCH 08/18] refactored radiobox, fixed bug Signed-off-by: Matt Bruce --- VDS/Components/RadioBox/RadioBox.swift | 30 +++++++------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/VDS/Components/RadioBox/RadioBox.swift b/VDS/Components/RadioBox/RadioBox.swift index f27a8809..0584079d 100644 --- a/VDS/Components/RadioBox/RadioBox.swift +++ b/VDS/Components/RadioBox/RadioBox.swift @@ -155,8 +155,6 @@ open class RadioBox: Control, Changeable { selectorStackView.addArrangedSubview(subTextRightLabel) selectorLeftLabelStackView.addArrangedSubview(textLabel) selectorLeftLabelStackView.addArrangedSubview(subTextLabel) - - updateSelector() selectorView.pinToSuperView() mainStackView.pinToSuperView(.init(top: 16, left: 16, bottom: 16, right: 16)) @@ -241,12 +239,12 @@ open class RadioBox: Control, Changeable { //-------------------------------------------------- // MARK: - State - //-------------------------------------------------- + //-------------------------------------------------- open override func updateView() { updateLabels() - updateSelector() updateAccessibilityLabel() - setNeedsDisplay() + setNeedsLayout() + layoutIfNeeded() } open override func updateAccessibilityLabel() { @@ -281,31 +279,19 @@ open class RadioBox: Control, Changeable { /// Manages the appearance of the radioBox. private var shapeLayer: CAShapeLayer? - - open func updateSelector() { + + open override func layoutSubviews() { + super.layoutSubviews() + //get the colors let backgroundColor = backgroundColorConfiguration.getColor(self) let borderColor = borderColorConfiguration.getColor(self) - let borderWidth = isSelected ? selectorBorderWidthSelected : selectorBorderWidth + let borderWidth = isSelected || isHighlighted ? selectorBorderWidthSelected : selectorBorderWidth selectorView.backgroundColor = backgroundColor selectorView.layer.borderColor = borderColor.cgColor selectorView.layer.cornerRadius = selectorCornerRadius selectorView.layer.borderWidth = borderWidth - - layer.setNeedsDisplay() - } - - open override func layoutSubviews() { - super.layoutSubviews() - // Accounts for any size changes - layer.setNeedsDisplay() - } - - open override func draw(_ layer: CALayer, in ctx: CGContext) { - - let borderColor = borderColorConfiguration.getColor(self) - shapeLayer?.removeFromSuperlayer() shapeLayer = nil From bdbc63e677b5e825b0b10857c3ae948099d8a1d4 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 10:59:24 -0500 Subject: [PATCH 09/18] refactored name to ReadioBoxItem Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 8 ++++---- VDS/Components/RadioBox/RadioBoxGroup.swift | 8 ++++---- .../RadioBox/{RadioBox.swift => RadioBoxItem.swift} | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) rename VDS/Components/RadioBox/{RadioBox.swift => RadioBoxItem.swift} (99%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 26d8ae24..80db9b43 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -57,7 +57,7 @@ EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */; }; EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; }; EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; }; - EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; }; + EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBoxItem.swift */; }; EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */; }; EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */; }; EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BE529688F6A00F2FF2E /* TileletBadgeModel.swift */; }; @@ -188,7 +188,7 @@ EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+VDSColor.swift"; sourceTree = ""; }; EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = ""; }; EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = ""; }; - EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = ""; }; + EA89201228B568D8006B9984 /* RadioBoxItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxItem.swift; sourceTree = ""; }; EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroup.swift; sourceTree = ""; }; EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyLabelAttribute.swift; sourceTree = ""; }; EA985BE529688F6A00F2FF2E /* TileletBadgeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletBadgeModel.swift; sourceTree = ""; }; @@ -590,7 +590,7 @@ EA89200B28B530F0006B9984 /* RadioBox */ = { isa = PBXGroup; children = ( - EA89201228B568D8006B9984 /* RadioBox.swift */, + EA89201228B568D8006B9984 /* RadioBoxItem.swift */, EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */, ); path = RadioBox; @@ -848,7 +848,7 @@ EA297A5729FB0A360031ED56 /* AppleGuidlinesTouchable.swift in Sources */, EA3361C328902D960071C351 /* Toggle.swift in Sources */, EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */, - EA89201328B568D8006B9984 /* RadioBox.swift in Sources */, + EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */, EAC9258C2911C9DE00091998 /* InputField.swift in Sources */, EA3362402892EF6C0071C351 /* Label.swift in Sources */, EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index 9c39bf19..3196de93 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -9,12 +9,12 @@ import Foundation import UIKit @objc(VDSRadioBoxGroup) -open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { +open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var selectorViews: [RadioBox] { + public override var selectorViews: [RadioBoxItem] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } @@ -33,7 +33,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { didSet { if let selectorModels { selectorViews = selectorModels.map { model in - return RadioBox().with { + return RadioBoxItem().with { $0.accessibilityLabel = model.accessibileText $0.text = model.text $0.textAttributes = model.textAttributes @@ -96,7 +96,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { }.store(in: &subscribers) } - open override func didSelect(_ selectedControl: RadioBox) { + open override func didSelect(_ selectedControl: RadioBoxItem) { let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first oldSelectedControl?.toggle() selectedControl.toggle() diff --git a/VDS/Components/RadioBox/RadioBox.swift b/VDS/Components/RadioBox/RadioBoxItem.swift similarity index 99% rename from VDS/Components/RadioBox/RadioBox.swift rename to VDS/Components/RadioBox/RadioBoxItem.swift index 0584079d..66d40542 100644 --- a/VDS/Components/RadioBox/RadioBox.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -11,8 +11,8 @@ import Combine import VDSColorTokens import VDSFormControlsTokens -@objc(VDSRadioBox) -open class RadioBox: Control, Changeable { +@objc(VDSRadioBoxItem) +open class RadioBoxItem: Control, Changeable { //-------------------------------------------------- // MARK: - Initializers From 05458e385b7f92410509da250bceb1f38b5da451 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:56:00 -0500 Subject: [PATCH 10/18] fixed bug adding onClick setup Signed-off-by: Matt Bruce --- VDS/Classes/SelectorBase.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/VDS/Classes/SelectorBase.swift b/VDS/Classes/SelectorBase.swift index 315aab1f..c7723e74 100644 --- a/VDS/Classes/SelectorBase.swift +++ b/VDS/Classes/SelectorBase.swift @@ -64,6 +64,13 @@ open class SelectorBase: Control, SelectorControlable { internal var shapeLayer: CAShapeLayer? + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() let layoutGuide = UILayoutGuide() @@ -85,6 +92,9 @@ open class SelectorBase: Control, SelectorControlable { layer.borderWidth = VDSFormControls.widthBorder } + + open func toggle() { } + open override func updateView() { super.updateView() From 16a6a41178034486e745f8e87f523dcbcdce87c3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:56:19 -0500 Subject: [PATCH 11/18] removed isAnimated Signed-off-by: Matt Bruce --- VDS/Classes/SelectorItemBase.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/VDS/Classes/SelectorItemBase.swift b/VDS/Classes/SelectorItemBase.swift index 3982843a..43501f92 100644 --- a/VDS/Classes/SelectorItemBase.swift +++ b/VDS/Classes/SelectorItemBase.swift @@ -89,9 +89,7 @@ open class SelectorItemBase: Control, Errorable, } open var selectorView = Selector() - - open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} - + open override var isSelected: Bool { didSet { setNeedsUpdate() }} open var labelText: String? { didSet { setNeedsUpdate() }} From 6b9747210318bf39f6cbe4a075027987d5c0b6f1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:56:56 -0500 Subject: [PATCH 12/18] bug for configuration Signed-off-by: Matt Bruce --- VDS/Classes/ColorConfiguration.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/VDS/Classes/ColorConfiguration.swift b/VDS/Classes/ColorConfiguration.swift index e0b3a7c1..3a4b468e 100644 --- a/VDS/Classes/ColorConfiguration.swift +++ b/VDS/Classes/ColorConfiguration.swift @@ -129,8 +129,10 @@ public class ControlColorConfiguration: KeyColorConfigurable { public func getColor(_ object: any ObjectType) -> UIColor { let state = object.state let surface = object.surface - - if let keyColor = keyColors.first(where: {$0.key.isSubset(of: state) }) { + + if let keyColor = keyColors.first(where: {$0.key == state }) { + return keyColor.surfaceConfig.getColor(surface) + } else if let keyColor = keyColors.first(where: {$0.key.isSubset(of: state) }) { return keyColor.surfaceConfig.getColor(surface) } else { return .clear From 53e14978c29f03c3b1ef990e2255f92c3cbdc06b Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:57:15 -0500 Subject: [PATCH 13/18] added property isAnimated Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/Checkbox.swift | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index bb47479d..886b1e8c 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -14,7 +14,7 @@ import VDSFormControlsTokens @objc(VDSCheckbox) open class Checkbox: SelectorBase { - open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} + open var isAnimated: Bool = false { didSet { setNeedsUpdate() }} open override func setup() { super.setup() @@ -24,10 +24,10 @@ open class Checkbox: SelectorBase { backgroundColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) @@ -36,6 +36,15 @@ open class Checkbox: SelectorBase { } + open override func toggle() { + //removed error + if showError && isSelected == false { + showError.toggle() + } + isSelected.toggle() + sendActions(for: .valueChanged) + } + open override func layoutSubviews() { super.layoutSubviews() From e8f0e7828a7b05d2b041109dc6cdf420fcaf2a20 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:57:35 -0500 Subject: [PATCH 14/18] added property for isanmiated Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/CheckboxItem.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Checkbox/CheckboxItem.swift b/VDS/Components/Checkbox/CheckboxItem.swift index d580d87a..675aa7cc 100644 --- a/VDS/Components/Checkbox/CheckboxItem.swift +++ b/VDS/Components/Checkbox/CheckboxItem.swift @@ -11,7 +11,11 @@ import UIKit /// 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(VDSCheckboxItem) open class CheckboxItem: SelectorItemBase { - + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open var isAnimated: Bool = false { didSet { setNeedsUpdate() }} + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- From bc0e051dfaa8d1a41d9b98aff6cd01b603677314 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 11:57:41 -0500 Subject: [PATCH 15/18] updated color Signed-off-by: Matt Bruce --- VDS/Components/RadioButton/RadioButton.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index 6c794f83..ac25b0f7 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -24,7 +24,7 @@ open class RadioButton: SelectorBase { borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled]) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) From 0e54cd307c08a6074949c2beea164eb2d7b4171e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 12:11:13 -0500 Subject: [PATCH 16/18] pushed down disabled and surface Signed-off-by: Matt Bruce --- VDS/Classes/SelectorItemBase.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VDS/Classes/SelectorItemBase.swift b/VDS/Classes/SelectorItemBase.swift index 43501f92..b9291e7c 100644 --- a/VDS/Classes/SelectorItemBase.swift +++ b/VDS/Classes/SelectorItemBase.swift @@ -265,6 +265,8 @@ open class SelectorItemBase: Control, Errorable, selectorView.showError = showError selectorView.isSelected = isSelected selectorView.isHighlighted = isHighlighted + selectorView.disabled = disabled + selectorView.surface = surface updateAccessibilityLabel() } From 8a5ecdc6b60acb98cf63c994284377848b259cb6 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 12:34:49 -0500 Subject: [PATCH 17/18] updated colors again for all use cases Signed-off-by: Matt Bruce --- VDS/Components/Checkbox/Checkbox.swift | 9 +++++---- VDS/Components/RadioButton/RadioButton.swift | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 886b1e8c..4cc4776a 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -20,9 +20,10 @@ open class Checkbox: SelectorBase { super.setup() backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected,.highlighted]) + backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected, .highlighted]) backgroundColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + backgroundColorConfig.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) @@ -30,10 +31,10 @@ open class Checkbox: SelectorBase { borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) - selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .disabled]) - selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: [.selected, .highlighted]) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) } open override func toggle() { diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index ac25b0f7..fd947ff4 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -20,13 +20,17 @@ open class RadioButton: SelectorBase { super.setup() backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - + backgroundColorConfig.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) + borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) + selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) selectorColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) From 6e7ff86b0bf15d35047ab88db772c1f4ad8310a1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 5 Jun 2023 12:57:40 -0500 Subject: [PATCH 18/18] refactored colorConfig -> colorConfiguration Signed-off-by: Matt Bruce --- VDS/Classes/SelectorBase.swift | 12 ++--- VDS/Components/Badge/Badge.swift | 4 +- VDS/Components/Checkbox/Checkbox.swift | 32 ++++++------- .../Icon/ButtonIcon/ButtonIcon.swift | 46 +++++++++---------- VDS/Components/Line/Line.swift | 4 +- VDS/Components/RadioButton/RadioButton.swift | 28 +++++------ VDS/Components/Tooltip/Tooltip.swift | 4 +- .../Tooltip/TooltipAlertViewController.swift | 2 +- 8 files changed, 66 insertions(+), 66 deletions(-) diff --git a/VDS/Classes/SelectorBase.swift b/VDS/Classes/SelectorBase.swift index c7723e74..9ba1066c 100644 --- a/VDS/Classes/SelectorBase.swift +++ b/VDS/Classes/SelectorBase.swift @@ -13,9 +13,9 @@ import VDSFormControlsTokens public protocol SelectorControlable: Control, Changeable { var showError: Bool { get set } var size: CGSize { get set } - var backgroundColorConfig: ControlColorConfiguration { get set } - var borderColorConfig: ControlColorConfiguration { get set } - var selectorColorConfig: ControlColorConfiguration { get set } + var backgroundColorConfiguration: ControlColorConfiguration { get set } + var borderColorConfiguration: ControlColorConfiguration { get set } + var selectorColorConfiguration: ControlColorConfiguration { get set } } open class SelectorBase: Control, SelectorControlable { @@ -50,11 +50,11 @@ open class SelectorBase: Control, SelectorControlable { } } - open var backgroundColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + open var backgroundColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} - open var borderColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + open var borderColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} - open var selectorColorConfig = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} //-------------------------------------------------- // MARK: - Constraints diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index 58562fd5..0d5fb623 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -86,7 +86,7 @@ open class Badge: View { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var backgroundColorConfig: AnyColorable = { + private var backgroundColorConfiguration: AnyColorable = { let config = KeyedColorConfiguration(keyPath: \.fillColor) config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) config.setSurfaceColors(VDSColor.paletteYellow53, VDSColor.paletteYellow53, forKey: .yellow) @@ -125,7 +125,7 @@ open class Badge: View { open override func updateView() { updateTextColorConfig() - backgroundColor = backgroundColorConfig.getColor(self) + backgroundColor = backgroundColorConfiguration.getColor(self) label.textColorConfiguration = textColorConfig.eraseToAnyColorable() label.numberOfLines = numberOfLines diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 4cc4776a..7ea46a3f 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -19,22 +19,22 @@ open class Checkbox: SelectorBase { open override func setup() { super.setup() - backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - backgroundColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected, .highlighted]) - backgroundColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) - backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - backgroundColorConfig.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) + backgroundColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + backgroundColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected, .highlighted]) + backgroundColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + backgroundColorConfiguration.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) + borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + borderColorConfiguration.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + borderColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) - selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) + selectorColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .selected) } open override func toggle() { @@ -50,9 +50,9 @@ open class Checkbox: SelectorBase { super.layoutSubviews() //get the colors - let backgroundColor = backgroundColorConfig.getColor(self) - let borderColor = borderColorConfig.getColor(self) - let selectorColor = selectorColorConfig.getColor(self) + let backgroundColor = backgroundColorConfiguration.getColor(self) + let borderColor = borderColorConfiguration.getColor(self) + let selectorColor = selectorColorConfiguration.getColor(self) if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index a7de9401..57e5c7f6 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -75,14 +75,14 @@ open class ButtonIcon: Control { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var iconColorConfig: AnyColorable { + private var iconColorConfiguration: AnyColorable { if selectedIconName != nil { - return selectedIconColorConfig + return selectedIconColorConfiguration } else { if kind == .highContrast { - return highContrastIconColorConfig + return highContrastIconColorConfiguration } else { - return standardIconColorConfig + return standardIconColorConfiguration } } } @@ -104,7 +104,7 @@ open class ButtonIcon: Control { } } - private var standardIconColorConfig: AnyColorable = { + private var standardIconColorConfiguration: AnyColorable = { return ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) @@ -112,11 +112,11 @@ open class ButtonIcon: Control { }.eraseToAnyColorable() }() - private var highContrastIconColorConfig: AnyColorable = { + private var highContrastIconColorConfiguration: AnyColorable = { return SurfaceColorConfiguration(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight).eraseToAnyColorable() }() - private var selectedIconColorConfig: AnyColorable = { + private var selectedIconColorConfiguration: AnyColorable = { return ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsBrandhighlight, VDSColor.elementsPrimaryOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) @@ -128,7 +128,7 @@ open class ButtonIcon: Control { var kind: Kind = .ghost var surfaceType: SurfaceType = .colorFill var floating: Bool = false - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(.clear, .clear).eraseToAnyColorable() }() } @@ -137,7 +137,7 @@ open class ButtonIcon: Control { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = false - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.paletteGray44.withAlphaComponent(0.06), VDSColor.paletteGray44.withAlphaComponent(0.26)).eraseToAnyColorable() }() } @@ -146,7 +146,7 @@ open class ButtonIcon: Control { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() }() } @@ -155,11 +155,11 @@ open class ButtonIcon: Control { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .media var floating: Bool = false - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() }() var borderWidth: CGFloat = 1.0 - var borderColorConfig: AnyColorable = { + var borderColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, .clear).eraseToAnyColorable() }() } @@ -168,10 +168,10 @@ open class ButtonIcon: Control { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .media var floating: Bool = true - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() }() - var shadowColorConfig: AnyColorable = { + var shadowColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() }() var shadowOpacity: CGFloat = 0.5 @@ -183,7 +183,7 @@ open class ButtonIcon: Control { var kind: Kind = .highContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = false - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { return ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) @@ -197,7 +197,7 @@ open class ButtonIcon: Control { var kind: Kind = .highContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true - var backgroundColorConfig: AnyColorable = { + var backgroundColorConfiguration: AnyColorable = { return ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) @@ -273,7 +273,7 @@ open class ButtonIcon: Control { //ensure there is an icon to set if let currentIconName { icon.name = currentIconName - let color = iconColorConfig.getColor(self) + let color = iconColorConfiguration.getColor(self) icon.color = color icon.size = size.value icon.customSize = customSize @@ -289,7 +289,7 @@ open class ButtonIcon: Control { let currentConfig = currentConfiguration - backgroundColor = currentConfig.backgroundColorConfig.getColor(self) + backgroundColor = currentConfig.backgroundColorConfiguration.getColor(self) // calculate center point for child view with offset let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) @@ -314,7 +314,7 @@ open class ButtonIcon: Control { //border if let borderable = currentConfig as? Borderable { - layer.borderColor = borderable.borderColorConfig.getColor(self).cgColor + layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor layer.borderWidth = borderable.borderWidth icon.layer.borderWidth = borderable.borderWidth } else { @@ -325,7 +325,7 @@ open class ButtonIcon: Control { if let dropshadowable = currentConfig as? Dropshadowable { layer.masksToBounds = false - layer.shadowColor = dropshadowable.shadowColorConfig.getColor(self).cgColor + layer.shadowColor = dropshadowable.shadowColorConfiguration.getColor(self).cgColor layer.shadowOpacity = Float(dropshadowable.shadowOpacity) layer.shadowOffset = dropshadowable.shadowOffset layer.shadowRadius = dropshadowable.shadowRadius @@ -362,11 +362,11 @@ extension ButtonIcon: AppleGuidlinesTouchable { private protocol Borderable { var borderWidth: CGFloat { get set } - var borderColorConfig: AnyColorable { get set } + var borderColorConfiguration: AnyColorable { get set } } private protocol Dropshadowable { - var shadowColorConfig: AnyColorable { get set } + var shadowColorConfiguration: AnyColorable { get set } var shadowOpacity: CGFloat { get set } var shadowOffset: CGSize { get set } var shadowRadius: CGFloat { get set } @@ -376,5 +376,5 @@ private protocol Configuration { var kind: ButtonIcon.Kind { get set } var surfaceType: ButtonIcon.SurfaceType { get set } var floating: Bool { get set } - var backgroundColorConfig: AnyColorable { get set } + var backgroundColorConfiguration: AnyColorable { get set } } diff --git a/VDS/Components/Line/Line.swift b/VDS/Components/Line/Line.swift index 2e74f9c4..4e038f7e 100644 --- a/VDS/Components/Line/Line.swift +++ b/VDS/Components/Line/Line.swift @@ -51,7 +51,7 @@ open class Line: View { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - public var lineViewColorConfig: AnyColorable = { + public var lineViewColorConfiguration: AnyColorable = { let config = KeyedColorConfiguration(keyPath: \.style) config.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forKey: .primary) config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary) @@ -62,6 +62,6 @@ open class Line: View { // MARK: - State //-------------------------------------------------- open override func updateView() { - lineView.backgroundColor = lineViewColorConfig.getColor(self) + lineView.backgroundColor = lineViewColorConfiguration.getColor(self) } } diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index fd947ff4..00e7134c 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -19,20 +19,20 @@ open class RadioButton: SelectorBase { open override func setup() { super.setup() - backgroundColorConfig.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) - backgroundColorConfig.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) + backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + backgroundColorConfiguration.setSurfaceColors(.clear, .clear, forState: [.error, .disabled]) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - borderColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - borderColorConfig.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - borderColorConfig.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) + borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + borderColorConfiguration.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + borderColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) - borderColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled]) - selectorColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - selectorColorConfig.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) + selectorColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + selectorColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) } @@ -40,9 +40,9 @@ open class RadioButton: SelectorBase { super.layoutSubviews() //get the colors - let backgroundColor = backgroundColorConfig.getColor(self) - let borderColor = borderColorConfig.getColor(self) - let selectorColor = selectorColorConfig.getColor(self) + let backgroundColor = backgroundColorConfiguration.getColor(self) + let borderColor = borderColorConfiguration.getColor(self) + let selectorColor = selectorColorConfiguration.getColor(self) if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() diff --git a/VDS/Components/Tooltip/Tooltip.swift b/VDS/Components/Tooltip/Tooltip.swift index 2ebb5247..6386daba 100644 --- a/VDS/Components/Tooltip/Tooltip.swift +++ b/VDS/Components/Tooltip/Tooltip.swift @@ -57,7 +57,7 @@ open class Tooltip: Control, TooltipLaunchable { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var iconColorConfig: AnyColorable { + private var iconColorConfiguration: AnyColorable { switch fillColor { case .primary: @@ -158,7 +158,7 @@ open class Tooltip: Control, TooltipLaunchable { widthConstraint?.constant = dimensions.width //get the color for the image - let imageColor = iconColorConfig.getColor(self) + let imageColor = iconColorConfiguration.getColor(self) imageView.image = infoImage.withTintColor(imageColor) accessibilityLabel = "Tooltip: \(title)" diff --git a/VDS/Components/Tooltip/TooltipAlertViewController.swift b/VDS/Components/Tooltip/TooltipAlertViewController.swift index 5de31cd0..e8e30a94 100644 --- a/VDS/Components/Tooltip/TooltipAlertViewController.swift +++ b/VDS/Components/Tooltip/TooltipAlertViewController.swift @@ -38,7 +38,7 @@ open class TooltipAlertViewController: UIViewController, Surfaceable { } private var line = Line().with { instance in - instance.lineViewColorConfig = SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable() + instance.lineViewColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable() } //--------------------------------------------------