diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index addff05e..db206376 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ EA33623E2892EE950071C351 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623D2892EE950071C351 /* UIDevice.swift */; }; EA3362402892EF6C0071C351 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623F2892EF6B0071C351 /* Label.swift */; }; EA33624728931B050071C351 /* Initable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33624628931B050071C351 /* Initable.swift */; }; + EA471F3A2A95587500CE9E58 /* LayoutConstraintable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */; }; EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */; }; EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */; }; EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB30128DCBCA500103EE3 /* Badge.swift */; }; @@ -139,6 +140,7 @@ EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */; }; EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */; }; EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */; }; + EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF978202A99035B00C2FEA9 /* Enabling.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -194,6 +196,7 @@ EA33623D2892EE950071C351 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = ""; }; EA33623F2892EF6B0071C351 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; }; EA33624628931B050071C351 /* Initable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Initable.swift; sourceTree = ""; }; + EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutConstraintable.swift; sourceTree = ""; }; EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorGroupHandlerBase.swift; sourceTree = ""; }; EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEquatable.swift; sourceTree = ""; }; EA4DB30128DCBCA500103EE3 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = ""; }; @@ -285,6 +288,7 @@ EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConfiguration.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 = ""; }; + EAF978202A99035B00C2FEA9 /* Enabling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Enabling.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -487,10 +491,12 @@ EAF1FE9829D4850E00101452 /* Clickable.swift */, EAA5EEDF28F49DB3003B3210 /* Colorable.swift */, EA3361A9288B25E40071C351 /* Disabling.swift */, + EAF978202A99035B00C2FEA9 /* Enabling.swift */, EA5E305929510F8B0082B959 /* EnumSubset.swift */, EAF7F0A1289AFB3900B287F5 /* Errorable.swift */, EA3361AE288B26310071C351 /* FormFieldable.swift */, EA33624628931B050071C351 /* Initable.swift */, + EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */, EA985C7C297DAED300F2FF2E /* Primitive.swift */, EAF7F0A5289B0CE000B287F5 /* Resetable.swift */, EA3361C8289054C50071C351 /* Surfaceable.swift */, @@ -963,6 +969,7 @@ EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */, EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */, EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */, + EA471F3A2A95587500CE9E58 /* LayoutConstraintable.swift in Sources */, EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */, EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */, EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */, @@ -977,6 +984,7 @@ EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */, EA513A952A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift in Sources */, 44604AD729CE196600E62B51 /* Line.swift in Sources */, + EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */, EA5E3058295105A40082B959 /* Tilelet.swift in Sources */, EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */, EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, @@ -1167,7 +1175,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 39; + CURRENT_PROJECT_VERSION = 40; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1204,7 +1212,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 39; + CURRENT_PROJECT_VERSION = 40; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/VDS/Classes/BundleManager.swift b/VDS/Classes/BundleManager.swift index 50537c0d..c5b90dd4 100644 --- a/VDS/Classes/BundleManager.swift +++ b/VDS/Classes/BundleManager.swift @@ -9,6 +9,14 @@ import Foundation import UIKit +public func DebugLog(_ message: String, file: String = #file, line: Int = #line, function: String = #function) { + #if DEBUG + let path = (file as NSString).lastPathComponent + // using print because NSLog crashes when passing certain optionals + print("[\(path)] \(function) [Line \(line)] : \(message)") + #endif +} + /// Bundle Manager keeps all bundles together for ease of use for searching within any of them for a specific asset public class BundleManager { public static var shared = BundleManager() diff --git a/VDS/Classes/ColorConfiguration.swift b/VDS/Classes/ColorConfiguration.swift index 317a16d3..4e1e8952 100644 --- a/VDS/Classes/ColorConfiguration.swift +++ b/VDS/Classes/ColorConfiguration.swift @@ -143,7 +143,7 @@ public class ControlColorConfiguration: KeyColorConfigurable { ///Meant to be used with any object that implements Surfaceable and Disabling. More than likely this is any View. public class ViewColorConfiguration: KeyColorConfigurable { public typealias KeyType = Bool - public typealias ObjectType = Surfaceable & Disabling + public typealias ObjectType = Surfaceable & Enabling public var keyColors: [KeyColorConfiguration] = [] public required init() { } @@ -161,7 +161,7 @@ public class ViewColorConfiguration: KeyColorConfigurable { /// - Parameter object: Object that implements Surfaceable and Disabling /// - Returns: UIColor correspoding to either true/false for the disabled state and surface public func getColor(_ object: ObjectType) -> UIColor { - if let keyColor = keyColors.first(where: {$0.key == object.disabled }) { + if let keyColor = keyColors.first(where: {$0.key == !object.isEnabled }) { return keyColor.surfaceConfig.getColor(object) } else { return .clear //default diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 10eb8ef9..cad40596 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -40,19 +40,12 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() } } - /// Whether this object is disabled or not - open var disabled: Bool { - get { !isEnabled } - set { - if !isEnabled != newValue { - isEnabled = !newValue - } - } - } - /// Whether the Control is selected or not. open override var isSelected: Bool { didSet { setNeedsUpdate() } } - + + /// Whether the Control can handle the isHighlighted state. + open var canHighlight: Bool = true + open var touchUpInsideCount: Int = 0 var isHighlightAnimating = false @@ -60,7 +53,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { /// Whether the Control is highlighted or not.. open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false && touchUpInsideCount > 0 { + if canHighlight && isHighlightAnimating == false && touchUpInsideCount > 0 { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.setNeedsUpdate() @@ -76,7 +69,12 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { } /// Whether the Control is enabled or not. - open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } + open override var isEnabled: Bool { + didSet { + setNeedsUpdate() + //isUserInteractionEnabled = isEnabled + } + } //-------------------------------------------------- // MARK: - Initializers @@ -137,7 +135,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { open func reset() { backgroundColor = .clear surface = .light - disabled = false + isEnabled = true } //-------------------------------------------------- diff --git a/VDS/Classes/SelectorGroupHandlerBase.swift b/VDS/Classes/SelectorGroupHandlerBase.swift index 868276ba..5d858bde 100644 --- a/VDS/Classes/SelectorGroupHandlerBase.swift +++ b/VDS/Classes/SelectorGroupHandlerBase.swift @@ -27,13 +27,11 @@ open class SelectorGroupHandlerBase: Control, Changeable { } } } - - /// Whether this object is disabled or not - override open var disabled: Bool { + + /// Whether this object is enabled or not + override open var isEnabled: Bool { didSet { - selectorViews.forEach { handler in - handler.disabled = disabled - } + selectorViews.forEach { $0.isEnabled = isEnabled } } } diff --git a/VDS/Classes/SelectorItemBase.swift b/VDS/Classes/SelectorItemBase.swift index b7c916b2..e7942bdb 100644 --- a/VDS/Classes/SelectorItemBase.swift +++ b/VDS/Classes/SelectorItemBase.swift @@ -33,7 +33,7 @@ open class SelectorItemBase: Control, Errorable, // MARK: - Private Properties //-------------------------------------------------- private var shouldShowError: Bool { - guard showError && !disabled && errorText?.isEmpty == false else { return false } + guard showError && isEnabled && errorText?.isEmpty == false else { return false } return true } @@ -191,7 +191,7 @@ open class SelectorItemBase: Control, Errorable, selectorView.showError = showError selectorView.isSelected = isSelected selectorView.isHighlighted = isHighlighted - selectorView.disabled = disabled + selectorView.isEnabled = isEnabled selectorView.surface = surface } @@ -237,7 +237,7 @@ open class SelectorItemBase: Control, Errorable, //top label if let labelText { label.surface = surface - label.disabled = disabled + label.isEnabled = isEnabled label.attributes = labelTextAttributes label.text = labelText label.isHidden = false @@ -252,7 +252,7 @@ open class SelectorItemBase: Control, Errorable, if let childText { childLabel.text = childText childLabel.surface = surface - childLabel.disabled = disabled + childLabel.isEnabled = isEnabled childLabel.attributes = childTextAttributes childLabel.isHidden = false @@ -276,7 +276,7 @@ open class SelectorItemBase: Control, Errorable, if let errorText, shouldShowError { errorLabel.text = errorText errorLabel.surface = surface - errorLabel.disabled = disabled + errorLabel.isEnabled = isEnabled mainStackView.spacing = 8 errorLabel.isHidden = false } else { diff --git a/VDS/Classes/View.swift b/VDS/Classes/View.swift index 8f1e40a3..e66a7448 100644 --- a/VDS/Classes/View.swift +++ b/VDS/Classes/View.swift @@ -33,18 +33,8 @@ open class View: UIView, ViewProtocol, UserInfoable { /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() } } - /// Whether this object is disabled or not. - open var disabled: Bool { - get { !isEnabled } - set { - if !isEnabled != newValue { - isEnabled = !newValue - } - } - } - /// Whether the View is enabled or not. - open var isEnabled: Bool = true { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } + open var isEnabled: Bool = true { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Initializers @@ -101,7 +91,7 @@ open class View: UIView, ViewProtocol, UserInfoable { open func reset() { backgroundColor = .clear surface = .light - disabled = false + isEnabled = true } } diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index bf2ff583..ef7569fb 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -27,9 +27,11 @@ open class Badge: View { /// Label used to render text open var label = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - $0.adjustsFontSizeToFitWidth = false $0.lineBreakMode = .byTruncatingTail + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentHuggingPriority(.defaultHigh, for: .vertical) + $0.setContentCompressionResistancePriority(.required, for: .horizontal) + $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) $0.textPosition = .left $0.textStyle = .boldBodySmall } @@ -37,7 +39,7 @@ open class Badge: View { /// This will render the badges fill color based on the available options. /// When used in conjunction with the surface prop, this fill color will change its tint automatically based on a light or dark surface. open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }} - + /// The text that will be shown in the label. open var text: String = "" { didSet { setNeedsUpdate() }} @@ -46,16 +48,27 @@ open class Badge: View { /// This will restrict the badge height to a specific number of lines. If the text overflows the allowable space, ellipsis will show. open var numberOfLines: Int = 1 { didSet { setNeedsUpdate() }} - + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- private var maxWidthConstraint: NSLayoutConstraint? - private var minWidthConstraint: NSLayoutConstraint? - + + private func updateMaxWidth() { + maxWidthConstraint?.isActive = false + guard let maxWidth, maxWidth > minWidth else { return } + maxWidthConstraint?.constant = maxWidth + maxWidthConstraint?.isActive = true + } + //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- + private var minWidth: CGFloat = 23.0 + private var labelInset: UIEdgeInsets = .init(top: 2, + left: VDSLayout.Spacing.space1X.value, + bottom: 2, + right: VDSLayout.Spacing.space1X.value) /// ColorConfiguration that is mapped to the 'fillColor' for the surface. private var backgroundColorConfiguration: AnyColorable = { @@ -96,23 +109,23 @@ open class Badge: View { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - + open override func setup() { super.setup() accessibilityElements = [label] layer.cornerRadius = 2 - + addSubview(label) - label.pinToSuperView(.init(top: 2, - left: VDSLayout.Spacing.space1X.value, - bottom: 2, - right: VDSLayout.Spacing.space1X.value)) - maxWidthConstraint = label.widthAnchor.constraint(lessThanOrEqualToConstant: 100) - minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23) - minWidthConstraint?.isActive = true + label + .pinTop(labelInset.top) + .pinLeading(labelInset.left) + .pinTrailing(labelInset.right) + .pinBottom(labelInset.bottom, .defaultHigh) + label.widthGreaterThanEqualTo(constant: minWidth) + maxWidthConstraint = label.widthLessThanEqualTo(constant: 0).with { $0.isActive = false } } /// Resets to default settings. @@ -136,20 +149,14 @@ open class Badge: View { super.updateView() updateTextColorConfig() - - backgroundColor = backgroundColorConfiguration.getColor(self) + updateMaxWidth() + backgroundColor = backgroundColorConfiguration.getColor(self) + label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() label.numberOfLines = numberOfLines label.text = text label.surface = surface - label.disabled = disabled - - if let maxWidth = maxWidth, let minWidth = minWidthConstraint?.constant, maxWidth > minWidth { - maxWidthConstraint?.constant = maxWidth - maxWidthConstraint?.isActive = true - } else { - maxWidthConstraint?.isActive = false - } + label.isEnabled = isEnabled } } diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index 25dd7a75..c71b4f31 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -258,19 +258,12 @@ open class BadgeIndicator: View { badgeView.addSubview(label) accessibilityElements = [label] - heightConstraint = badgeView.heightAnchor.constraint(greaterThanOrEqualToConstant: badgeSize) - heightConstraint?.isActive = true - - widthConstraint = badgeView.widthAnchor.constraint(greaterThanOrEqualToConstant: badgeSize) - widthConstraint?.isActive = true + heightConstraint = badgeView.heightGreaterThanEqualTo(constant: badgeSize) + widthConstraint = badgeView.widthGreaterThanEqualTo(constant: badgeSize) //we are insetting the padding to compensate for the border - NSLayoutConstraint.activate([ - badgeView.topAnchor.constraint(equalTo: topAnchor, constant: borderWidth), - badgeView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -borderWidth), - badgeView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: borderWidth), - badgeView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -borderWidth)]) - + badgeView.pinToSuperView(.init(top: borderWidth, left: borderWidth, bottom: borderWidth, right: borderWidth)) + labelContraints.topConstraint = label.pinTopGreaterThanOrEqualTo(anchor: badgeView.topAnchor) labelContraints.bottomConstraint = label.pinBottomGreaterThanOrEqualTo(anchor: badgeView.bottomAnchor) labelContraints.leadingConstraint = label.pinLeadingGreaterThanOrEqualTo(anchor: badgeView.leadingAnchor) @@ -348,7 +341,7 @@ open class BadgeIndicator: View { label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() label.text = getText() label.surface = surface - label.disabled = disabled + label.isEnabled = isEnabled label.sizeToFit() setNeedsLayout() layoutIfNeeded() diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index f81e3b40..b91f1a5c 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -22,9 +22,6 @@ open class Button: ButtonBase, Useable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - private var minWidthConstraint: NSLayoutConstraint? - private var widthConstraint: NSLayoutConstraint? - private var heightConstraint: NSLayoutConstraint? private var initialSetupPerformed = false //-------------------------------------------------- @@ -36,7 +33,18 @@ open class Button: ButtonBase, Useable { open var size: ButtonSize = .large { didSet { setNeedsUpdate() }} - open var width: CGFloat? { didSet { setNeedsUpdate() }} + private var _width: CGFloat? = nil + open var width: CGFloat? { + get { _width } + set { + if let newValue, newValue > size.minimumWidth { + _width = newValue + } else { + _width = nil + } + setNeedsUpdate() + } + } open override var textColor: UIColor { textColorConfiguration.getColor(self) @@ -120,14 +128,6 @@ open class Button: ButtonBase, Useable { super.setup() isAccessibilityElement = true accessibilityTraits = .button - - //only 1 of the 2 widths can be on at the same time - widthConstraint = widthAnchor.constraint(equalToConstant: 0) - minWidthConstraint = widthAnchor.constraint(greaterThanOrEqualToConstant: size.minimumWidth) - - //height - heightConstraint = heightAnchor.constraint(equalToConstant: 0) - heightConstraint?.isActive = true } /// Resets to default settings. @@ -145,7 +145,12 @@ open class Button: ButtonBase, Useable { // MARK: - Overrides //-------------------------------------------------- open override var intrinsicContentSize: CGSize { - guard let width, width > 0 else { return super.intrinsicContentSize } + guard let width, width > 0 else { + var superSize = super.intrinsicContentSize + superSize.height = size.height + return superSize + } + return CGSize(width: width > size.minimumWidth ? width : size.minimumWidth, height: size.height) } @@ -156,9 +161,7 @@ open class Button: ButtonBase, Useable { let bgColor = backgroundColorConfiguration.getColor(self) let borderColor = borderColorConfiguration.getColor(self) let borderWidth = use == .secondary ? VDSFormControls.widthBorder : 0.0 - let buttonHeight = size.height let cornerRadius = size.cornerRadius - let minWidth = size.minimumWidth let edgeInsets = size.edgeInsets backgroundColor = bgColor @@ -166,18 +169,8 @@ open class Button: ButtonBase, Useable { layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth contentEdgeInsets = edgeInsets - - minWidthConstraint?.constant = minWidth - heightConstraint?.constant = buttonHeight - - if let width, width > minWidth { - widthConstraint?.constant = width - widthConstraint?.isActive = true - minWidthConstraint?.isActive = false - } else { - widthConstraint?.isActive = false - minWidthConstraint?.isActive = true - } + + invalidateIntrinsicContentSize() } } diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 2f1e23b5..d8c3add4 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -11,7 +11,7 @@ import VDSColorTokens import VDSFormControlsTokens import Combine -public protocol Buttonable: UIControl, Surfaceable, Disabling { +public protocol Buttonable: UIControl, Surfaceable, Enabling { var availableSizes: [ButtonSize] { get } var text: String? { get set } var intrinsicContentSize: CGSize { get } @@ -83,19 +83,9 @@ open class ButtonBase: UIButton, Buttonable, ViewProtocol, UserInfoable, Clickab } } } - - /// Whether this object is disabled or not - open var disabled: Bool { - get { !isEnabled } - set { - if !isEnabled != newValue { - isEnabled = !newValue - } - } - } - + /// Whether the Control is enabled or not. - open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } + open override var isEnabled: Bool { didSet { setNeedsUpdate() } } open var textStyle: TextStyle { .defaultStyle } @@ -144,7 +134,7 @@ open class ButtonBase: UIButton, Buttonable, ViewProtocol, UserInfoable, Clickab open func reset() { shouldUpdateView = false surface = .light - disabled = false + isEnabled = true text = nil accessibilityCustomActions = [] shouldUpdateView = true diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 99aef7f5..e0db8b10 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -93,13 +93,10 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// Whether this object is disabled or not - override open var disabled: Bool { + /// Whether this object is enabled or not + override open var isEnabled: Bool { didSet { - buttons.forEach { button in - var b = button - b.disabled = disabled - } + buttons.forEach { $0.isEnabled = isEnabled } } } @@ -130,12 +127,13 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega //-------------------------------------------------- // MARK: - Public Functions //-------------------------------------------------- + open override func setup() { super.setup() addSubview(collectionView) collectionView.pinToSuperView() } - + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -150,11 +148,12 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega open override func layoutSubviews() { super.layoutSubviews() // Accounts for any collection size changes - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self else { return } self.collectionView.collectionViewLayout.invalidateLayout() } } - + //-------------------------------------------------- // MARK: - UICollectionViewDataSource //-------------------------------------------------- @@ -195,5 +194,4 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable { buttons[indexPath.row] } - } diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index ca7aac1d..8b6ea74b 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -18,6 +18,10 @@ open class TextLink: ButtonBase { // MARK: - Private Properties //-------------------------------------------------- private var lineHeightConstraint: NSLayoutConstraint? + + private var line = UIView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } //-------------------------------------------------- // MARK: - Properties @@ -64,10 +68,6 @@ open class TextLink: ButtonBase { super.init(coder: coder) } - private var line = UIView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - //-------------------------------------------------- // MARK: - Public Functions //-------------------------------------------------- @@ -75,15 +75,15 @@ open class TextLink: ButtonBase { super.setup() isAccessibilityElement = true accessibilityTraits = .link + if let titleLabel { addSubview(line) line.pinLeading(titleLabel.leadingAnchor) line.pinTrailing(titleLabel.trailingAnchor) line.pinTop(titleLabel.bottomAnchor) - line.pinBottom(bottomAnchor) - lineHeightConstraint = line.heightAnchor.constraint(equalToConstant: 1.0) + line.pinBottom(bottomAnchor, 0, .defaultHigh) + lineHeightConstraint = line.height(constant: 1) lineHeightConstraint?.isActive = true - titleLabel.debugBorder(show: true) } } @@ -92,7 +92,7 @@ open class TextLink: ButtonBase { super.reset() shouldUpdateView = false text = nil - size = .large + size = .large accessibilityCustomActions = [] isAccessibilityElement = true accessibilityTraits = .link diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index a41ebfb0..2e75e6a3 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -119,7 +119,7 @@ extension TextLinkCaret { } func setAttribute(on attributedString: NSMutableAttributedString) { - let imageAttr = ImageLabelAttribute(location: location, imageName: "\(position.rawValue)-caret-bold", frame: .init(x: 0, y: 0, width: caretSize.width, height: caretSize.height), tintColor: tintColor) + let imageAttr = ImageLabelAttribute(location: location, imageName: "\(position.rawValue)-caret-bold", frame: .init(x: 0, y: 0, width: caretSize.width, height: caretSize.height), tintColor: tintColor, accessibleText: "Caret") let spacer = NSAttributedString.spacer(for: spacerWidth) guard let image = try? imageAttr.getAttachment() else { return } diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 9c22e616..1179e58e 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -99,7 +99,7 @@ open class Checkbox: SelectorBase { shapeLayer?.removeAllAnimations() - if isAnimated && !disabled && !isHighlighted { + if isAnimated && isEnabled && !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 763a18ab..c5cd4d9e 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -40,7 +40,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in return CheckboxItem().with { - $0.disabled = model.disabled + $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId $0.value = model.value @@ -110,7 +110,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { } extension CheckboxGroup { - public struct CheckboxModel : Surfaceable, Disabling, Initable, FormFieldable, Errorable { + public struct CheckboxModel : Surfaceable, Initable, FormFieldable, Errorable { /// Whether this object is disabled or not public var disabled: Bool diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 00efaca1..63e8000a 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -235,22 +235,17 @@ open class ButtonIcon: Control { addSubview(icon) //determines the height/width of the icon - layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) - layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) + layoutGuideWidthConstraint = iconLayoutGuide.width(constant: size.containerSize) + layoutGuideHeightConstraint = iconLayoutGuide.height(constant: size.containerSize) + //pin layout guide + iconLayoutGuide.pinToSuperView() + //determines the center point of the icon centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) + centerXConstraint?.activate() centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) - - //activate the constraints - NSLayoutConstraint.activate([layoutGuideWidthConstraint!, - layoutGuideHeightConstraint!, - centerXConstraint!, - centerYConstraint!, - iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor), - iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) + centerYConstraint?.activate() } /// Resets to default settings. diff --git a/VDS/Components/Icon/Icon.swift b/VDS/Components/Icon/Icon.swift index 0c496793..58a515db 100644 --- a/VDS/Components/Icon/Icon.swift +++ b/VDS/Components/Icon/Icon.swift @@ -16,8 +16,10 @@ open class Icon: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - private var widthConstraint: NSLayoutConstraint? - private var heightConstraint: NSLayoutConstraint? + private var dimensions: CGSize { + guard let customSize else { return size.dimensions } + return .init(width: customSize, height: customSize) + } //-------------------------------------------------- // MARK: - Public Properties @@ -42,20 +44,20 @@ open class Icon: View { //functions //-------------------------------------------------- - // MARK: - Lifecycle + // MARK: - Overrides //-------------------------------------------------- open override func setup() { super.setup() + setContentCompressionResistancePriority(.required, for: .vertical) + setContentHuggingPriority(.required, for: .vertical) + setContentCompressionResistancePriority(.required, for: .horizontal) + setContentHuggingPriority(.required, for: .horizontal) + addSubview(imageView) imageView.pinToSuperView() - heightConstraint = imageView.heightAnchor.constraint(equalToConstant: size.dimensions.height) - heightConstraint?.isActive = true - widthConstraint = imageView.widthAnchor.constraint(equalToConstant: size.dimensions.width) - widthConstraint?.isActive = true - backgroundColor = .clear isAccessibilityElement = true @@ -68,6 +70,10 @@ open class Icon: View { color = VDSColor.paletteBlack imageView.image = nil } + + open override var intrinsicContentSize: CGSize { + dimensions + } /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { @@ -81,17 +87,7 @@ open class Icon: View { } else if surface == .light && color == VDSColor.paletteBlack { imageColor = VDSColor.elementsPrimaryOnlight } - - //set the icon dimensions - var dimensions = size.dimensions - - if let customSize { - dimensions = .init(width: customSize, height: customSize) - } - - heightConstraint?.constant = dimensions.height - widthConstraint?.constant = dimensions.width - + //get the image name //set the image if let name, let image = getImage(for: name.rawValue) { @@ -99,8 +95,10 @@ open class Icon: View { } else { imageView.image = nil } - } + invalidateIntrinsicContentSize() + } + private func getImage(for imageName: String) -> UIImage? { return BundleManager.shared.image(for: imageName) diff --git a/VDS/Components/Label/Attributes/ActionLabelAttribute.swift b/VDS/Components/Label/Attributes/ActionLabelAttribute.swift index 4a29f613..67241895 100644 --- a/VDS/Components/Label/Attributes/ActionLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/ActionLabelAttribute.swift @@ -38,18 +38,17 @@ public struct ActionLabelAttribute: ActionLabelAttributeModel { public var length: Int public var shouldUnderline: Bool public var accessibleText: String? - public var action: PassthroughSubject + public var action = PassthroughSubject() public var subscriber: AnyCancellable? //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- - public init(location: Int, length: Int, shouldUnderline: Bool = true, accessibleText: String? = nil, action: PassthroughSubject = .init() ) { + public init(location: Int, length: Int, shouldUnderline: Bool = true, accessibleText: String? = nil) { self.location = location self.length = length self.shouldUnderline = shouldUnderline self.accessibleText = accessibleText - self.action = action } private enum CodingKeys: String, CodingKey { @@ -67,3 +66,19 @@ public struct ActionLabelAttribute: ActionLabelAttributeModel { extension NSAttributedString.Key { public static let action = NSAttributedString.Key(rawValue: "action") } + +extension String { + public func nsRange(of text: String) -> NSRange? { + guard let found = range(of: text) else { return nil } + return NSRange(found, in: self) + } +} + + +extension ActionLabelAttribute { + + public init? (text: String, linkText: String, accessibleText: String? = nil) { + guard let range = text.nsRange(of: linkText) else { return nil } + self.init(location: range.location, length: range.length) + } +} diff --git a/VDS/Components/Label/Attributes/ImageLabelAttribute.swift b/VDS/Components/Label/Attributes/ImageLabelAttribute.swift index dcd98629..7cc2f224 100644 --- a/VDS/Components/Label/Attributes/ImageLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/ImageLabelAttribute.swift @@ -28,7 +28,8 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel { public var image: UIImage? public var frame: CGRect? public var tintColor: UIColor? - + public var accessibleText: String? + //-------------------------------------------------- // MARK: - Equatable //-------------------------------------------------- @@ -40,11 +41,27 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel { return id == equatable.id && range == equatable.range && imageName == equatable.imageName } + public init(id: UUID = UUID(), location: Int, imageName: String? = nil, image: UIImage? = nil, frame: CGRect? = nil, tintColor: UIColor? = nil, accessibleText: String? = nil) { + self.id = id + self.location = location + self.imageName = imageName + self.image = image + self.frame = frame + self.tintColor = tintColor + self.accessibleText = accessibleText + } + //-------------------------------------------------- // MARK: - Private Functions //-------------------------------------------------- private func imageAttachment(image: UIImage) -> NSTextAttachment { let attachment = NSTextAttachment() + if let accessibleText { + attachment.accessibilityLabel = accessibleText + attachment.isAccessibilityElement = true + } else { + attachment.isAccessibilityElement = false + } attachment.image = tintColor != nil ? image.withTintColor(tintColor!) : image if let frame { attachment.bounds = frame diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index d77e03fe..26867749 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -68,9 +68,8 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable addHandler(on: attributedString) } - public init(id: UUID = UUID(), action: PassthroughSubject = PassthroughSubject(), subscriber: AnyCancellable? = nil, surface: Surface, accessibleText: String? = nil, closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil, presenter: UIView? = nil) { + public init(id: UUID = UUID(), subscriber: AnyCancellable? = nil, surface: Surface, accessibleText: String? = nil, closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil, presenter: UIView? = nil) { self.id = id - self.action = action self.subscriber = subscriber self.surface = surface self.accessibleText = accessibleText diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 27f3fd79..45777f5b 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -44,25 +44,19 @@ open class Label: UILabel, ViewProtocol, UserInfoable { open var userInfo = [String: Primitive]() + open override var numberOfLines: Int { didSet { setNeedsUpdate() }} + + open override var lineBreakMode: NSLineBreakMode { didSet { setNeedsUpdate() }} + override open var text: String? { didSet { attributes = nil setNeedsUpdate() } } - - /// Whether this object is disabled or not - open var disabled: Bool { - get { !isEnabled } - set { - if !isEnabled != newValue { - isEnabled = !newValue - } - } - } - + /// Whether the View is enabled or not. - open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } + open override var isEnabled: Bool { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration Properties @@ -119,7 +113,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { open func reset() { shouldUpdateView = false surface = .light - disabled = false + isEnabled = true attributes = nil textStyle = .defaultStyle textPosition = .left diff --git a/VDS/Components/Line/Line.swift b/VDS/Components/Line/Line.swift index c9c33aba..e64e7406 100644 --- a/VDS/Components/Line/Line.swift +++ b/VDS/Components/Line/Line.swift @@ -19,15 +19,16 @@ open class Line: View { case primary, secondary } + public enum Orientation: String, CaseIterable { + case horizontal, vertical + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var lineView = UIView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - open var style: Style = .primary { didSet { setNeedsUpdate() } } - + open var orientation: Orientation = .horizontal { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- @@ -37,29 +38,37 @@ open class Line: View { config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary) return config.eraseToAnyColorable() }() - + //-------------------------------------------------- - // MARK: - Lifecycle + // MARK: - Overrides //-------------------------------------------------- - - open override func setup() { - super.setup() - - addSubview(lineView) - lineView.height(1) - lineView.pinToSuperView() + + open override var intrinsicContentSize: CGSize { + if orientation == .vertical { + return .init(width: 1, height: bounds.height) + } else { + return .init(width: bounds.width, height: 1) + } } /// Resets to default settings. open override func reset() { super.reset() style = .primary + orientation = .horizontal + } + + open override func setup() { + super.setup() } /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - - lineView.backgroundColor = lineViewColorConfiguration.getColor(self) + + backgroundColor = lineViewColorConfiguration.getColor(self) + + invalidateIntrinsicContentSize() } + } diff --git a/VDS/Components/Loader/Loader.swift b/VDS/Components/Loader/Loader.swift index 9c67b6e2..9fd4e4e3 100644 --- a/VDS/Components/Loader/Loader.swift +++ b/VDS/Components/Loader/Loader.swift @@ -27,7 +27,14 @@ open class Loader: View { open var isActive: Bool = true { didSet { setNeedsUpdate() } } /// The Int used to determine the height and width of the Loader - open var size: Int = 40 { didSet { setNeedsUpdate() } } + open var size: Int = 40 { + didSet { + setNeedsUpdate(); + invalidateIntrinsicContentSize() + } + } + + open override var intrinsicContentSize: CGSize { .init(width: size, height: size) } //-------------------------------------------------- // MARK: - Lifecycle @@ -36,13 +43,15 @@ open class Loader: View { super.setup() addSubview(icon) + icon + .pinTopGreaterThanOrEqualTo() + .pinLeadingGreaterThanOrEqualTo() + .pinTrailingLessThanOrEqualTo() + .pinBottomLessThanOrEqualTo() + NSLayoutConstraint.activate([ icon.centerXAnchor.constraint(equalTo: centerXAnchor), - icon.centerYAnchor.constraint(equalTo: centerYAnchor), - icon.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor), - icon.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor), - icon.topAnchor.constraint(greaterThanOrEqualTo: topAnchor), - icon.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor) + icon.centerYAnchor.constraint(equalTo: centerYAnchor) ]) } diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index 209a5769..2443bc74 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -43,7 +43,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { $0.subTextAttributes = model.subTextAttributes $0.subTextRight = model.subText $0.subTextRightAttributes = model.subTextAttributes - $0.disabled = model.disabled + $0.isEnabled = !model.disabled $0.inputId = model.inputId $0.isSelected = model.selected } @@ -106,7 +106,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { } extension RadioBoxGroup { - public struct RadioBoxModel: Surfaceable, Initable, Disabling, FormFieldable { + public struct RadioBoxModel: Surfaceable, Initable, FormFieldable { /// Whether this object is disabled or not public var disabled: Bool /// Current Surface and this is used to pass down to child objects that implement Surfacable diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index e789785e..b9f16b5e 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -187,14 +187,14 @@ open class RadioBoxItem: Control, Changeable { //text label textLabel.text = text textLabel.surface = surface - textLabel.disabled = disabled + textLabel.isEnabled = isEnabled textLabel.attributes = textAttributes //subText label if let subText { subTextLabel.text = subText subTextLabel.surface = surface - subTextLabel.disabled = disabled + subTextLabel.isEnabled = isEnabled subTextLabel.attributes = subTextAttributes subTextLabel.isHidden = false @@ -209,7 +209,7 @@ open class RadioBoxItem: Control, Changeable { if let subTextRight { subTextRightLabel.text = subTextRight subTextRightLabel.surface = surface - subTextRightLabel.disabled = disabled + subTextRightLabel.isEnabled = isEnabled subTextRightLabel.attributes = subTextRightAttributes subTextRightLabel.isHidden = false diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 4298f827..90e8bba7 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -35,7 +35,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in return RadioButtonItem().with { - $0.disabled = model.disabled + $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId $0.value = model.value @@ -114,7 +114,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { } extension RadioButtonGroup { - public struct RadioButtonModel: Surfaceable, Disabling, Initable, FormFieldable, Errorable { + public struct RadioButtonModel: Surfaceable, Initable, FormFieldable, Errorable { /// Whether this object is disabled or not public var disabled: Bool diff --git a/VDS/Components/RadioSwatch/RadioSwatch.swift b/VDS/Components/RadioSwatch/RadioSwatch.swift index 1658482d..9f61b4ec 100644 --- a/VDS/Components/RadioSwatch/RadioSwatch.swift +++ b/VDS/Components/RadioSwatch/RadioSwatch.swift @@ -176,13 +176,13 @@ open class RadioSwatch: Control { var fillColorBackground: UIColor = .clear if let fillImage { - fillView.image = disabled ? fillImage.image(alpha: disabledAlpha) : fillImage + fillView.image = !isEnabled ? fillImage.image(alpha: disabledAlpha) : fillImage } else { fillView.image = nil if let primary = primaryColor, let secondary = secondaryColor { - let firstColor = disabled ? primary.withAlphaComponent(disabledAlpha) : primary - let secondColor = disabled ? secondary.withAlphaComponent(disabledAlpha) : secondary + let firstColor = !isEnabled ? primary.withAlphaComponent(disabledAlpha) : primary + let secondColor = !isEnabled ? secondary.withAlphaComponent(disabledAlpha) : secondary let gradient = CAGradientLayer() gradientLayer = gradient gradient.frame = fillView.bounds @@ -195,7 +195,7 @@ open class RadioSwatch: Control { } } - fillView.backgroundColor = disabled ? fillColorBackground.withAlphaComponent(disabledAlpha) : fillColorBackground + fillView.backgroundColor = !isEnabled ? fillColorBackground.withAlphaComponent(disabledAlpha) : fillColorBackground fillView.layer.borderColor = fillBorderColor.cgColor fillView.layer.cornerRadius = fillView.bounds.width * 0.5 fillView.layer.borderWidth = selectorBorderWidth diff --git a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift index 25827392..98cc0d44 100644 --- a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift +++ b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift @@ -32,7 +32,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo $0.primaryColor = model.primaryColor $0.secondaryColor = model.secondaryColor $0.strikethrough = model.strikethrough - $0.disabled = model.disabled + $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId $0.value = model.value @@ -71,15 +71,15 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + /// Whether this object is disabled or not - override public var disabled: Bool { + override public var isEnabled: Bool { didSet { - for selector in selectorViews { - selector.disabled = disabled - } + selectorViews.forEach { $0.isEnabled = isEnabled } collectionView.reloadData() } } + /// Current Surface and this is used to pass down to child objects that implement Surfacable override public var surface: Surface { didSet { @@ -132,7 +132,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo label.textStyle = .bodySmall label.text = selectedHandler?.text ?? " " label.surface = surface - label.disabled = disabled + label.isEnabled = isEnabled collectionView.reloadData() } @@ -151,7 +151,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo // MARK: - UICollectionViewDelegate //-------------------------------------------------- open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { - return !selectorViews[indexPath.row].disabled + return selectorViews[indexPath.row].isEnabled } open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { @@ -193,7 +193,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo } extension RadioSwatchGroup { - public struct RadioSwatchModel: Surfaceable, Disabling, Initable { + public struct RadioSwatchModel: Surfaceable, Initable { /// Whether this object is disabled or not public var disabled: Bool = false /// Current Surface and this is used to pass down to child objects that implement Surfacable diff --git a/VDS/Components/Tabs/Tab.swift b/VDS/Components/Tabs/Tab.swift index d33bea63..16a39935 100644 --- a/VDS/Components/Tabs/Tab.swift +++ b/VDS/Components/Tabs/Tab.swift @@ -95,12 +95,11 @@ extension Tabs { private let layoutGuide = UILayoutGuide() - private var widthConstraint: NSLayoutConstraint? { - if let width, orientation == .vertical { - return layoutGuide.widthAnchor.constraint(equalToConstant: width) - } else { - return layoutGuide.widthAnchor.constraint(greaterThanOrEqualToConstant: minWidth) - } + private func updateWidth() { + labelWidthConstraint?.isActive = false + guard let width, width > minWidth else { return } + labelWidthConstraint?.constant = width + labelWidthConstraint?.isActive = true } //-------------------------------------------------- @@ -124,27 +123,26 @@ extension Tabs { open override func setup() { super.setup() + + canHighlight = false + addLayoutGuide(layoutGuide) addSubview(label) accessibilityTraits = .button isAccessibilityElement = true - //activate the constraints - NSLayoutConstraint.activate([layoutGuide.topAnchor.constraint(equalTo: topAnchor), - layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) + //pin layoutguide + layoutGuide.pinToSuperView() + //pin trailing label.pinTrailing(layoutGuide.trailingAnchor) - - labelTopConstraint = label.topAnchor.constraint(equalTo: layoutGuide.topAnchor) - labelTopConstraint?.isActive = true - - labelBottomConstraint = label.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor) - labelBottomConstraint?.isActive = true - - labelLeadingConstraint = label.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor) - labelLeadingConstraint?.isActive = true + + //setup constraints + labelWidthConstraint = layoutGuide.width(constant: 0).with { $0.isActive = false } + layoutGuide.widthGreaterThanEqualTo(minWidth) + labelTopConstraint = label.pinTop(anchor: layoutGuide.topAnchor) + labelLeadingConstraint = label.pinLeading(anchor: layoutGuide.leadingAnchor) + labelBottomConstraint = label.pinBottom(anchor: layoutGuide.bottomAnchor, priority: .defaultHigh) } /// Function used to make changes to the View based off a change events or from local properties. @@ -156,9 +154,7 @@ extension Tabs { accessibilityIdentifier = "VDSTab:\(text)" //constaints - labelWidthConstraint?.isActive = false - labelWidthConstraint = widthConstraint - labelWidthConstraint?.isActive = true + updateWidth() labelLeadingConstraint?.constant = leadingSpace labelTopConstraint?.constant = otherSpace labelBottomConstraint?.constant = -otherSpace @@ -169,7 +165,6 @@ extension Tabs { label.textStyle = textStyle label.textPosition = textPosition label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() - setNeedsLayout() layoutIfNeeded() diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index 548178e5..cd138d60 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -144,6 +144,10 @@ open class Tabs: View { orientation == .horizontal && fillContainer ? .center : .left } + private var applyOverflow: Bool { + orientation == .horizontal && overflow == .scroll && !fillContainer + } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -187,20 +191,20 @@ open class Tabs: View { contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true - borderlineViewWidthConstraint = borderlineView.widthAnchor.constraint(equalToConstant: 0) - borderlineViewHeightConstraint = borderlineView.heightAnchor.constraint(equalToConstant: 0) + borderlineViewWidthConstraint = borderlineView.width(constant: 0) + borderlineViewHeightConstraint = borderlineView.height(constant: 0) - borderlineViewLeadingConstraint = borderlineView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor) - borderlineViewTrailingConstraint = borderlineView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) - borderlineViewTopConstraint = borderlineView.topAnchor.constraint(equalTo: contentView.topAnchor) - borderlineViewBottomConstraint = borderlineView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) + borderlineViewLeadingConstraint = borderlineView.pinLeading(anchor: contentView.leadingAnchor) + borderlineViewTrailingConstraint = borderlineView.pinTrailing(anchor: contentView.trailingAnchor) + borderlineViewTopConstraint = borderlineView.pinTop(anchor: contentView.topAnchor) + borderlineViewBottomConstraint = borderlineView.pinBottom(anchor: contentView.bottomAnchor) } /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - + updateStackView() updateTabs() updateContentView() @@ -258,7 +262,9 @@ open class Tabs: View { /// Updates the Tab individual views from local properties. private func updateTabs() { + let numberOfLines = applyOverflow ? 1 : 0 for (index, tabItem) in tabViews.enumerated() { + tabItem.label.numberOfLines = numberOfLines tabItem.size = size tabItem.isSelected = selectedIndex == index tabItem.index = index @@ -277,10 +283,10 @@ open class Tabs: View { contentViewWidthConstraint?.isActive = false // Apply overflow - if orientation == .horizontal && overflow == .scroll && !fillContainer { - let contentWidth = tabStackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width + if applyOverflow { contentViewWidthConstraint = nil - scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.bounds.height) + scrollView.contentSize = CGSize(width: tabStackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width, + height: scrollView.bounds.height) } else { contentViewWidthConstraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor) scrollView.contentSize = bounds.size @@ -294,6 +300,11 @@ open class Tabs: View { scrollToSelectedIndex(animated: true) } + open override func layoutSubviews() { + super.layoutSubviews() + updateContentView() + } + //update layout for borderline private func updateBorderline() { //borderLine diff --git a/VDS/Components/Tabs/TabsContainer.swift b/VDS/Components/Tabs/TabsContainer.swift index 50eab591..0b8db53d 100644 --- a/VDS/Components/Tabs/TabsContainer.swift +++ b/VDS/Components/Tabs/TabsContainer.swift @@ -132,12 +132,7 @@ open class TabsContainer: View { stackView.addArrangedSubview(tabMenu) stackView.addArrangedSubview(contentView) - NSLayoutConstraint.activate([ - tabMenuLayoutGuide.topAnchor.constraint(equalTo: topAnchor), - tabMenuLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - tabMenuLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - tabMenuLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor) - ]) + tabMenuLayoutGuide.pinToSuperView() } /// Function used to make changes to the View based off a change events or from local properties. @@ -168,7 +163,7 @@ open class TabsContainer: View { contentViewWidthConstraint?.isActive = true tabMenu.surface = surface - tabMenu.disabled = disabled + tabMenu.isEnabled = isEnabled tabMenu.orientation = orientation tabMenu.borderLine = borderLine tabMenu.fillContainer = fillContainer diff --git a/VDS/Components/TextFields/EntryField/EntryField.swift b/VDS/Components/TextFields/EntryField/EntryField.swift index 819e805e..933d53ee 100644 --- a/VDS/Components/TextFields/EntryField/EntryField.swift +++ b/VDS/Components/TextFields/EntryField/EntryField.swift @@ -283,7 +283,7 @@ open class EntryField: Control, Changeable { //dealing with the "Optional" addition to the text if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") { - if !disabled { + if isEnabled { let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2, length: 8, color: VDSColor.elementsSecondaryOnlight) @@ -301,20 +301,19 @@ open class EntryField: Control, Changeable { titleLabel.text = updatedLabelText titleLabel.attributes = attributes titleLabel.surface = surface - titleLabel.disabled = disabled - + titleLabel.isEnabled = isEnabled } open func updateErrorLabel(){ if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface - errorLabel.disabled = disabled + errorLabel.isEnabled = isEnabled errorLabel.isHidden = false icon.name = .error icon.color = VDSColor.paletteBlack icon.surface = surface - icon.isHidden = disabled + icon.isHidden = !isEnabled } else { icon.isHidden = true errorLabel.isHidden = true @@ -326,7 +325,7 @@ open class EntryField: Control, Changeable { if let helperText { helperLabel.text = helperText helperLabel.surface = surface - helperLabel.disabled = disabled + helperLabel.isEnabled = isEnabled helperLabel.isHidden = false } else { helperLabel.isHidden = true diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f6df3da8..eb7ca72a 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -165,7 +165,7 @@ open class InputField: EntryField, UITextFieldDelegate { open override func updateView() { super.updateView() - textField.isEnabled = !disabled + textField.isEnabled = isEnabled textField.textColor = textFieldTextColorConfiguration.getColor(self) //show error or success @@ -175,13 +175,13 @@ open class InputField: EntryField, UITextFieldDelegate { } else if showSuccess, let successText { successLabel.text = successText successLabel.surface = surface - successLabel.disabled = disabled + successLabel.isEnabled = isEnabled successLabel.isHidden = false errorLabel.isHidden = true icon.name = .checkmarkAlt icon.color = VDSColor.paletteBlack icon.surface = surface - icon.isHidden = disabled + icon.isHidden = !isEnabled } else { icon.isHidden = true successLabel.isHidden = true diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index eb7e45e0..6d94399f 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -95,7 +95,7 @@ open class TextArea: EntryField { open override func updateView() { super.updateView() - textView.isEditable = !disabled + textView.isEditable = isEnabled textView.textColor = textViewTextColorConfiguration.getColor(self) //set the width constraints diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index e96f9f04..45a6dbaf 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -168,14 +168,10 @@ open class TileContainer: Control { containerView.backgroundColor = .clear - containerTopConstraint = containerView.topAnchor.constraint(equalTo: topAnchor, constant: padding.value) - containerTopConstraint?.isActive = true - containerBottomConstraint = containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: padding.value) - containerBottomConstraint?.isActive = true - containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.value) - containerLeadingConstraint?.isActive = true - containerTrailingConstraint = containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: padding.value) - containerTrailingConstraint?.isActive = true + containerTopConstraint = containerView.pinTop(anchor: topAnchor, constant: padding.value) + containerBottomConstraint = containerView.pinBottom(anchor: bottomAnchor, constant: padding.value) + containerLeadingConstraint = containerView.pinLeading(anchor: leadingAnchor, constant: padding.value) + containerTrailingConstraint = containerView.pinTrailing(anchor: trailingAnchor, constant: padding.value) highlightView.pinToSuperView() highlightView.isHidden = true diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index bf3ea8f0..2b1dd4db 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -43,7 +43,7 @@ open class TitleLockup: View { private var stackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .vertical - $0.distribution = .fill + $0.distribution = .fillProportionally } private var otherStandardStyle: OtherStandardStyle { @@ -269,8 +269,11 @@ open class TitleLockup: View { stackView.addArrangedSubview(subTitleLabel) //pin stackview to edges - stackView.pinToSuperView() - + stackView + .pinTop() + .pinLeading() + .pinTrailing() + .pinBottom(0, .defaultHigh) } /// Resets to default settings. @@ -311,7 +314,6 @@ open class TitleLockup: View { eyebrowLabel.attributes = eyebrowModel.textAttributes eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines eyebrowLabel.surface = surface - //When uniform size is true if let titleModel, isUniformSize { if titleModel.isBold { @@ -329,8 +331,6 @@ open class TitleLockup: View { eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular } - } else { - eyebrowLabel.reset() } if let titleModel, !titleModel.text.isEmpty { @@ -341,8 +341,6 @@ open class TitleLockup: View { titleLabel.attributes = titleModel.textAttributes titleLabel.numberOfLines = titleModel.numberOfLines titleLabel.surface = surface - } else { - titleLabel.reset() } if let subTitleModel, !subTitleModel.text.isEmpty { @@ -354,8 +352,6 @@ open class TitleLockup: View { subTitleLabel.attributes = subTitleModel.textAttributes subTitleLabel.numberOfLines = subTitleModel.numberOfLines subTitleLabel.surface = surface - } else { - subTitleLabel.reset() } //if both first 2 rows not empty set spacing @@ -376,5 +372,5 @@ open class TitleLockup: View { eyebrowLabel.isHidden = eyebrowTextIsEmpty titleLabel.isHidden = titleTextIsEmpty subTitleLabel.isHidden = subTitleTextIsEmpty - } + } } diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 82a602b2..9f030d90 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -86,6 +86,7 @@ open class Toggle: Control, Changeable { open var toggleView = ToggleView().with { $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) $0.isUserInteractionEnabled = false + $0.isAccessibilityElement = false } open var label = Label().with { @@ -140,34 +141,35 @@ open class Toggle: Control, Changeable { open override func setup() { super.setup() - + + canHighlight = false isAccessibilityElement = true accessibilityTraits = .button addSubview(label) addSubview(toggleView) - let heightEqual = heightAnchor.constraint(equalToConstant: toggleContainerSize.height) - heightEqual.priority = .defaultLow - - let heightGreater = heightAnchor.constraint(greaterThanOrEqualToConstant: toggleContainerSize.height) - heightGreater.priority = .defaultHigh + label.widthLessThanEqualTo(labelMaxWidth) // Set up initial constraints for label and switch toggleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true labelConstraints = [ - heightEqual, heightGreater, - label.widthAnchor.constraint(lessThanOrEqualToConstant: labelMaxWidth), + height(constant: toggleContainerSize.height, priority: .defaultLow), + heightGreaterThanEqualTo(constant: toggleContainerSize.height, priority: .defaultHigh), label.topAnchor.constraint(equalTo: topAnchor), label.bottomAnchor.constraint(equalTo: bottomAnchor), ] leftConstraints = [ - toggleView.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: spacingBetween) + toggleView.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: spacingBetween), + label.leadingAnchor.constraint(equalTo: leadingAnchor), + toggleView.trailingAnchor.constraint(equalTo: trailingAnchor) ] rightConstraints = [ - label.leadingAnchor.constraint(equalTo: toggleView.trailingAnchor, constant: spacingBetween) + toggleView.leadingAnchor.constraint(equalTo: leadingAnchor), + label.leadingAnchor.constraint(equalTo: toggleView.trailingAnchor, constant: spacingBetween), + label.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) ] } @@ -177,6 +179,7 @@ open class Toggle: Control, Changeable { super.reset() shouldUpdateView = false label.reset() + isEnabled = true isOn = false isAnimated = true showText = false @@ -197,7 +200,7 @@ open class Toggle: Control, Changeable { updateLabel() toggleView.surface = surface - toggleView.disabled = disabled + toggleView.isEnabled = isEnabled toggleView.isOn = isOn } @@ -223,6 +226,7 @@ open class Toggle: Control, Changeable { private var showLabel: Bool { showText && !statusText.isEmpty } + private func updateLabel() { label.isHidden = !showLabel @@ -231,7 +235,7 @@ open class Toggle: Control, Changeable { label.textStyle = textStyle label.text = statusText label.surface = surface - label.disabled = disabled + label.isEnabled = isEnabled switch textPosition { case .left: NSLayoutConstraint.deactivate(rightConstraints) @@ -246,7 +250,6 @@ open class Toggle: Control, Changeable { NSLayoutConstraint.deactivate(rightConstraints) NSLayoutConstraint.deactivate(labelConstraints) } - invalidateIntrinsicContentSize() } //-------------------------------------------------- diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index bc17ffe3..58292cc4 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -117,19 +117,22 @@ open class ToggleView: Control, Changeable { isAccessibilityElement = true accessibilityTraits = .button - + addSubview(toggleView) toggleView.addSubview(knobView) - - NSLayoutConstraint.activate([ - toggleView.widthAnchor.constraint(equalToConstant: toggleSize.width), - toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height), - toggleView.centerYAnchor.constraint(equalTo: centerYAnchor), - knobView.heightAnchor.constraint(equalToConstant: knobSize.height), - knobView.widthAnchor.constraint(equalToConstant: knobSize.width), - knobView.centerYAnchor.constraint(equalTo: toggleView.centerYAnchor), - knobView.topAnchor.constraint(greaterThanOrEqualTo: toggleView.topAnchor) - ]) + + toggleView.pinToSuperView() + + toggleView + .width(toggleSize.width) + .height(toggleSize.height) + + knobView + .pinTopGreaterThanOrEqualTo() + .width(knobSize.width) + .height(knobSize.height) + + knobView.centerYAnchor.constraint(equalTo: toggleView.centerYAnchor).activate() // Set cornerRadius knobView.layer.cornerRadius = knobSize.height / 2.0 @@ -145,20 +148,7 @@ open class ToggleView: Control, Changeable { // Update shadow layers frames to match the view's bounds knobView.layer.insertSublayer(shadowLayer1, at: 0) knobView.layer.insertSublayer(shadowLayer2, at: 0) - - let shadowColor = VDSColor.paletteBlack.cgColor - shadowLayer1.cornerRadius = knobView.layer.cornerRadius - shadowLayer1.shadowColor = shadowColor - shadowLayer1.shadowOpacity = 0.24 - shadowLayer1.shadowOffset = .init(width: 0, height: 1) - shadowLayer1.shadowRadius = 5.0 - - shadowLayer2.cornerRadius = knobView.layer.cornerRadius - shadowLayer2.shadowColor = shadowColor - shadowLayer2.shadowOpacity = 0.08 - shadowLayer2.shadowOffset = .init(width: 0, height: 2) - shadowLayer2.shadowRadius = 2.0 - + } /// Resets to default settings. @@ -225,7 +215,7 @@ open class ToggleView: Control, Changeable { shadowLayer1.backgroundColor = knobColor.cgColor shadowLayer2.backgroundColor = knobColor.cgColor - if disabled || !isAnimated { + if !isEnabled || !isAnimated { toggleView.backgroundColor = toggleColor knobView.backgroundColor = knobColor constrainKnob() @@ -246,6 +236,19 @@ open class ToggleView: Control, Changeable { shadowLayer1.frame = knobView.bounds shadowLayer2.frame = knobView.bounds + + let shadowColor = isEnabled ? VDSColor.paletteBlack.cgColor : VDSColor.paletteGray95.cgColor + shadowLayer1.cornerRadius = knobView.layer.cornerRadius + shadowLayer1.shadowColor = shadowColor + shadowLayer1.shadowOpacity = isEnabled ? 0.24 : 0.1 + shadowLayer1.shadowOffset = .init(width: 0, height: 1) + shadowLayer1.shadowRadius = isEnabled ? 5.0 : 10.0 + + shadowLayer2.cornerRadius = knobView.layer.cornerRadius + shadowLayer2.shadowColor = shadowColor + shadowLayer2.shadowOpacity = isEnabled ? 0.08 : 0.04 + shadowLayer2.shadowOffset = .init(width: 0, height: 2) + shadowLayer2.shadowRadius = 2.0 } } diff --git a/VDS/Components/Tooltip/Tooltip.swift b/VDS/Components/Tooltip/Tooltip.swift index c522137f..d3adc11d 100644 --- a/VDS/Components/Tooltip/Tooltip.swift +++ b/VDS/Components/Tooltip/Tooltip.swift @@ -38,10 +38,10 @@ open class Tooltip: Control, TooltipLaunchable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var imageView = UIImageView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.contentMode = .scaleAspectFill - $0.clipsToBounds = true + open var icon = Icon().with { + $0.name = .info + $0.size = .small + $0.isUserInteractionEnabled = false } open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }} @@ -111,18 +111,8 @@ open class Tooltip: Control, TooltipLaunchable { open override func setup() { super.setup() - if let image = BundleManager.shared.image(for: "info") { - infoImage = image - } - - addSubview(imageView) - - imageView.pinToSuperView() - heightConstraint = imageView.heightAnchor.constraint(equalToConstant: size.value.dimensions.height) - heightConstraint?.isActive = true - widthConstraint = imageView.widthAnchor.constraint(equalToConstant: size.value.dimensions.width) - widthConstraint?.isActive = true - + addSubview(icon) + icon.pinToSuperView() backgroundColor = .clear isAccessibilityElement = true @@ -149,7 +139,6 @@ open class Tooltip: Control, TooltipLaunchable { content = "" fillColor = .primary closeButtonText = "Close" - imageView.image = nil shouldUpdateView = true setNeedsUpdate() } @@ -157,15 +146,12 @@ open class Tooltip: Control, TooltipLaunchable { /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - - //set the dimensions - let dimensions = size.value.dimensions - heightConstraint?.constant = dimensions.height - widthConstraint?.constant = dimensions.width + + //get the size + icon.size = size.value //get the color for the image - let imageColor = iconColorConfiguration.getColor(self) - imageView.image = infoImage.withTintColor(imageColor) + icon.color = iconColorConfiguration.getColor(self) } open override func updateAccessibility() { diff --git a/VDS/Components/Tooltip/TrailingTooltipLabel.swift b/VDS/Components/Tooltip/TrailingTooltipLabel.swift index 4a1be607..0555a5a9 100644 --- a/VDS/Components/Tooltip/TrailingTooltipLabel.swift +++ b/VDS/Components/Tooltip/TrailingTooltipLabel.swift @@ -71,8 +71,8 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { label.textPosition = labelTextPosition label.attributes = labelAttributes label.surface = surface - label.disabled = disabled - + label.isEnabled = isEnabled + //add tooltip if let labelText, !labelText.isEmpty { label.addTooltip(model: .init(surface: surface, closeButtonText: tooltipCloseButtonText, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView)) diff --git a/VDS/Extensions/UIView+NSLayoutConstraint.swift b/VDS/Extensions/UIView+NSLayoutConstraint.swift index 8bc4f28f..e53dc1d5 100644 --- a/VDS/Extensions/UIView+NSLayoutConstraint.swift +++ b/VDS/Extensions/UIView+NSLayoutConstraint.swift @@ -10,466 +10,11 @@ import UIKit import VDSFormControlsTokens extension UIView { - public func constraint(with identifier: String) -> NSLayoutConstraint? { return constraints.first { $0.identifier == identifier } } } -//-------------------------------------------------- -// MARK: - Pinning -//-------------------------------------------------- -extension UIView { - @discardableResult - /// Pins each to the all 4 anchor points to a view. - /// - Parameters: - /// - view: View that you will be pinned within. - /// - edges: Insets for each side. - /// - Returns: Yourself. - public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { - pinLeading(view.leadingAnchor, edges.left) - pinTrailing(view.trailingAnchor, edges.right) - pinTop(view.topAnchor, edges.top) - pinBottom(view.bottomAnchor, edges.bottom) - return self - } - - @discardableResult - - /// Pins each to the all 4 anchor points to the view you are set within. - /// - Parameter edges: Insets for each side. - /// - Returns: Yourself. - public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { - if let superview { - pin(superview, with: edges) - } - return self - } -} - -//-------------------------------------------------- -// MARK: - HeightAnchor -//-------------------------------------------------- -extension UIView { - - @discardableResult - /// Adds a heightAnchor. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func height(_ constant: CGFloat) -> Self { - height(constant: constant) - return self - } - - @discardableResult - /// Adds a heightAnchor where the height constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func heightGreaterThanEqualTo(_ constant: CGFloat) -> Self { - heightGreaterThanEqualTo(constant: constant) - return self - } - - @discardableResult - /// Adds a heightAnchor where the height constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func heightLessThanEqualTo(_ constant: CGFloat) -> Self { - heightLessThanEqualTo(constant: constant) - return self - } - - @discardableResult - /// Adds a heightAnchor for the constant passed into the method. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func height(constant: CGFloat) -> NSLayoutConstraint { - heightAnchor.constraint(equalToConstant: constant).activate() - } - - @discardableResult - /// Adds a heightAnchor where the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func heightGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { - heightAnchor.constraint(greaterThanOrEqualToConstant: constant).activate() - } - - @discardableResult - /// Adds a heightAnchor where the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func heightLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { - heightAnchor.constraint(lessThanOrEqualToConstant: constant).activate() - } - -} - -//-------------------------------------------------- -// MARK: - WidthAnchor -//-------------------------------------------------- -extension UIView { - - @discardableResult - /// Adds a widthAnchor. - /// - Parameter constant: Width Constant size. - /// - Returns: Yourself. - public func width(_ constant: CGFloat) -> Self { - width(constant: constant) - return self - } - - @discardableResult - /// Adds a widthAnchor where the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func widthGreaterThanEqualTo(_ constant: CGFloat) -> Self { - widthGreaterThanEqualTo(constant: constant) - return self - } - - @discardableResult - /// Adds a widthAnchor where the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func widthLessThanEqualTo(_ constant: CGFloat) -> Self { - widthLessThanEqualTo(constant: constant) - return self - } - - @discardableResult - /// Adds a widthAnchor for the constant passed into the method. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func width(constant: CGFloat) -> NSLayoutConstraint { - widthAnchor.constraint(equalToConstant: constant).activate() - } - - @discardableResult - /// Adds a widthAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func widthGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { - widthAnchor.constraint(greaterThanOrEqualToConstant: constant).activate() - } - - @discardableResult - /// Adds a widthAnchor with the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter constant: Constant size. - /// - Returns: The Constraint that was created. - public func widthLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { - widthAnchor.constraint(lessThanOrEqualToConstant: constant).activate() - } -} - -//-------------------------------------------------- -// MARK: - TopAnchor -//-------------------------------------------------- -extension UIView { - - @discardableResult - /// Adds a topAnchor. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func pinTop(_ constant: CGFloat = 0.0) -> Self { - return pinTop(nil, constant) - } - - @discardableResult - /// Adds a topAnchor to a specific YAxisAnchor. - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTop(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a topAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTopLessThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a topAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTopGreaterThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a topAnchor for the constant passed into the method. - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - guard let found else { return nil } - return topAnchor.constraint(equalTo: found, constant: constant).activate() - } - - @discardableResult - /// Adds a topAnchor with the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - guard let found else { return nil } - return topAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() - } - - @discardableResult - /// Adds a topAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the topAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - guard let found else { return nil } - return topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() - } - -} - -//-------------------------------------------------- -// MARK: - BottomAnchor -//-------------------------------------------------- -extension UIView { - @discardableResult - /// Adds a bottomAnchor. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func pinBottom(_ constant: CGFloat = 0.0) -> Self { - return pinBottom(nil, constant) - } - - @discardableResult - /// Adds a bottomAnchor to a specific YAxisAnchor. - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinBottom(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a bottomAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a bottomAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinBottomGreaterThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a bottomAnchor for the constant passed into the method. - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - guard let found else { return nil } - return bottomAnchor.constraint(equalTo: found, constant: -constant).activate() - } - - @discardableResult - /// Adds a bottomAnchor with the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - guard let found else { return nil } - return bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() - } - - @discardableResult - /// Adds a bottomAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the bottomAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - guard let found else { return nil } - return bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() - } -} - -//-------------------------------------------------- -// MARK: - LeadingAnchor -//-------------------------------------------------- -extension UIView { - - @discardableResult - /// Adds a leadingAnchor. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func pinLeading(_ constant: CGFloat = 0.0) -> Self { - return pinLeading(nil, constant) - } - - @discardableResult - /// Adds a leadingAnchor to a specific XAxisAnchor. - /// - Parameter anchor:The anchor in which to attach the leadingAnchor. - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinLeading(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the leadingAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinLeadingLessThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the leadingAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinLeadingGreaterThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a leadingAnchor for the constant passed into the method. - /// - Parameter anchor:The anchor in which to attach the leadingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - guard let found else { return nil } - return leadingAnchor.constraint(equalTo: found, constant: constant).activate() - } - - @discardableResult - /// Adds a leadingAnchor with the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the leadingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - guard let found else { return nil } - return leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() - } - - @discardableResult - /// Adds a leadingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the leadingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - guard let found else { return nil } - return leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() - } -} - -//-------------------------------------------------- -// MARK: - TrailingAnchor -//-------------------------------------------------- -extension UIView { - - @discardableResult - /// Adds a trailingAnchor. - /// - Parameter constant: Constant size. - /// - Returns: Yourself. - public func pinTrailing(_ constant: CGFloat = 0.0) -> Self { - pinTrailing(nil, constant) - } - - @discardableResult - /// Adds a trailingAnchor to a specific XAxisAnchor. - /// - Parameter anchor:The anchor in which to attach the trailingAnchor. - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTrailing(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a trailingAnchor to a specific XAxisAnchor passed in using a lessThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the trailingAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a trailingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint - /// - Parameter anchor:The anchor in which to attach the trailingAnchor - /// - constant: Constant size. - /// - Returns: Yourself. - public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - pinTrailingGreaterThanOrEqualTo(anchor: anchor, constant: constant) - return self - } - - @discardableResult - /// Adds a trailingAnchor for the constant passed into the method. - /// - Parameter anchor:The anchor in which to attach the trailingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - guard let found else { return nil } - return trailingAnchor.constraint(equalTo: found, constant: -constant).activate() - } - - @discardableResult - /// Adds a trailingAnchor with the constant passed in using a lessThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the trailingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - guard let found else { return nil } - return trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() - } - - @discardableResult - /// Adds a trailingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. - /// - Parameter anchor:The anchor in which to attach the trailingAnchor - /// - constant: Constant size. - /// - Returns: The Constraint that was created. - public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - guard let found else { return nil } - return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() - } -} - extension NSLayoutConstraint { @discardableResult diff --git a/VDS/Protocols/Disabling.swift b/VDS/Protocols/Disabling.swift index 51a5bb50..12b938a7 100644 --- a/VDS/Protocols/Disabling.swift +++ b/VDS/Protocols/Disabling.swift @@ -7,8 +7,8 @@ import Foundation -/// Any object that can be disabled, which may change the appearance -public protocol Disabling { - /// Whether this object is disabled or not - var disabled: Bool { get set } -} +///// Any object that can be disabled, which may change the appearance +//public protocol Disabling { +// /// Whether this object is disabled or not +// var disabled: Bool { get set } +//} diff --git a/VDS/Protocols/Enabling.swift b/VDS/Protocols/Enabling.swift new file mode 100644 index 00000000..b6e429ef --- /dev/null +++ b/VDS/Protocols/Enabling.swift @@ -0,0 +1,14 @@ +// +// Enabling.swift +// VDS +// +// Created by Matt Bruce on 8/25/23. +// + +import Foundation + +/// Any object that can be Enabled, which may change the appearance +public protocol Enabling { + /// Whether this object is enabled or not + var isEnabled: Bool { get set } +} diff --git a/VDS/Protocols/LayoutConstraintable.swift b/VDS/Protocols/LayoutConstraintable.swift new file mode 100644 index 00000000..ceededbc --- /dev/null +++ b/VDS/Protocols/LayoutConstraintable.swift @@ -0,0 +1,490 @@ +// +// LayoutConstraintable.swift +// VDS +// +// Created by Matt Bruce on 8/22/23. +// + +import Foundation +import UIKit +import VDSFormControlsTokens + +public protocol LayoutConstraintable { + var superview: UIView? { get } + + var leadingAnchor: NSLayoutXAxisAnchor { get } + var trailingAnchor: NSLayoutXAxisAnchor { get } + var topAnchor: NSLayoutYAxisAnchor { get } + var bottomAnchor: NSLayoutYAxisAnchor { get } + + var widthAnchor: NSLayoutDimension { get } + var heightAnchor: NSLayoutDimension { get } + + var centerXAnchor: NSLayoutXAxisAnchor { get } + var centerYAnchor: NSLayoutYAxisAnchor { get } +} + +//-------------------------------------------------- +// MARK: - Pinning +//-------------------------------------------------- +extension LayoutConstraintable { + @discardableResult + /// Pins each to the all 4 anchor points to a view. + /// - Parameters: + /// - view: View that you will be pinned within. + /// - edges: Insets for each side. + /// - Returns: Yourself. + public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { + pinLeading(view.leadingAnchor, edges.left) + pinTrailing(view.trailingAnchor, edges.right) + pinTop(view.topAnchor, edges.top) + pinBottom(view.bottomAnchor, edges.bottom) + return self + } + + @discardableResult + + /// Pins each to the all 4 anchor points to the view you are set within. + /// - Parameter edges: Insets for each side. + /// - Returns: Yourself. + public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { + if let superview { + pin(superview, with: edges) + } + return self + } +} + +//-------------------------------------------------- +// MARK: - HeightAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a heightAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func height(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + height(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a heightAnchor where the height constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func heightGreaterThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + heightGreaterThanEqualTo(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a heightAnchor where the height constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func heightLessThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + heightLessThanEqualTo(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a heightAnchor for the constant passed into the method. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func height(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + heightAnchor.constraint(equalToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a heightAnchor where the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func heightGreaterThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + heightAnchor.constraint(greaterThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a heightAnchor where the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func heightLessThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + heightAnchor.constraint(lessThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } + +} + +//-------------------------------------------------- +// MARK: - WidthAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a widthAnchor. + /// - Parameter constant: Width Constant size. + /// - Returns: Yourself. + public func width(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + width(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a widthAnchor where the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func widthGreaterThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + widthGreaterThanEqualTo(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a widthAnchor where the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func widthLessThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self { + widthLessThanEqualTo(constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a widthAnchor for the constant passed into the method. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func width(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + widthAnchor.constraint(equalToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a widthAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func widthGreaterThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + widthAnchor.constraint(greaterThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a widthAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter constant: Constant size. + /// - Returns: The Constraint that was created. + public func widthLessThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint { + widthAnchor.constraint(lessThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true } + } +} + +//-------------------------------------------------- +// MARK: - TopAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a topAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinTop(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + return pinTop(nil, constant, priority) + } + + @discardableResult + /// Adds a topAnchor to a specific YAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTop(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a topAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTopLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a topAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTopGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a topAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(equalTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a topAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(lessThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a topAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the topAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } + +} + +//-------------------------------------------------- +// MARK: - BottomAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + @discardableResult + /// Adds a bottomAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinBottom(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + return pinBottom(nil, constant, priority) + } + + @discardableResult + /// Adds a bottomAnchor to a specific YAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinBottom(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a bottomAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a bottomAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinBottomGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a bottomAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a bottomAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a bottomAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the bottomAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } +} + +//-------------------------------------------------- +// MARK: - LeadingAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a leadingAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinLeading(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + return pinLeading(nil, constant, priority) + } + + @discardableResult + /// Adds a leadingAnchor to a specific XAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the leadingAnchor. + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinLeading(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the leadingAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinLeadingLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the leadingAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinLeadingGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority) + return self + } + + @discardableResult + /// Adds a leadingAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the leadingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(equalTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a leadingAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the leadingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a leadingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the leadingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true } + } +} + +//-------------------------------------------------- +// MARK: - TrailingAnchor +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a trailingAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinTrailing(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTrailing(nil, constant) + } + + @discardableResult + /// Adds a trailingAnchor to a specific XAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the trailingAnchor. + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTrailing(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a trailingAnchor to a specific XAxisAnchor passed in using a lessThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the trailingAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a trailingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the trailingAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + pinTrailingGreaterThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a trailingAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the trailingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a trailingAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the trailingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a trailingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the trailingAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } +} + + +//-------------------------------------------------- +// MARK: - Implementations +//-------------------------------------------------- +extension UIView: LayoutConstraintable {} +extension UILayoutGuide: LayoutConstraintable { + public var superview: UIView? { + owningView + } +} diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index 47b9f9b0..f6d878c3 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -9,7 +9,7 @@ import Foundation import UIKit import Combine -public protocol ViewProtocol: AnyObject, Initable, Resettable, Disabling, Surfaceable { +public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surfaceable { /// Set of Subscribers for any Publishers for this Control. var subscribers: Set { get set } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 42e22558..a84fb8d4 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,9 @@ +1.0.40 +======= +- Refactored a bit of code to remove "disabled" and move to "isEnabled" Apple Standard. +- Fixed Layout Constraint issues +- Added fixes for Accessibility + 1.0.39 ======= - CXTDT-423141 - Tabs - Selected Tab dark mode text color