Merge branch 'refactor/enabling' into 'develop'

fix for button

See merge request BPHV_MIPS/vds_ios!103
This commit is contained in:
Bruce, Matt R 2023-08-25 21:40:42 +00:00
commit 53c2a63dbb
47 changed files with 887 additions and 829 deletions

View File

@ -48,6 +48,7 @@
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623D2892EE950071C351 /* UIDevice.swift */; }; EA33623E2892EE950071C351 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623D2892EE950071C351 /* UIDevice.swift */; };
EA3362402892EF6C0071C351 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623F2892EF6B0071C351 /* Label.swift */; }; EA3362402892EF6C0071C351 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33623F2892EF6B0071C351 /* Label.swift */; };
EA33624728931B050071C351 /* Initable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33624628931B050071C351 /* Initable.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 */; }; EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */; };
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */; }; EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */; };
EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB30128DCBCA500103EE3 /* Badge.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 */; }; EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */; };
EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */; }; EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */; };
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.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 */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -194,6 +196,7 @@
EA33623D2892EE950071C351 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; }; EA33623D2892EE950071C351 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
EA33623F2892EF6B0071C351 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; }; EA33623F2892EF6B0071C351 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
EA33624628931B050071C351 /* Initable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Initable.swift; sourceTree = "<group>"; }; EA33624628931B050071C351 /* Initable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Initable.swift; sourceTree = "<group>"; };
EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutConstraintable.swift; sourceTree = "<group>"; };
EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorGroupHandlerBase.swift; sourceTree = "<group>"; }; EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorGroupHandlerBase.swift; sourceTree = "<group>"; };
EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEquatable.swift; sourceTree = "<group>"; }; EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEquatable.swift; sourceTree = "<group>"; };
EA4DB30128DCBCA500103EE3 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = "<group>"; }; EA4DB30128DCBCA500103EE3 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = "<group>"; };
@ -285,6 +288,7 @@
EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConfiguration.swift; sourceTree = "<group>"; }; EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConfiguration.swift; sourceTree = "<group>"; };
EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonItem.swift; sourceTree = "<group>"; }; EAF7F11528A1475A00B287F5 /* RadioButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonItem.swift; sourceTree = "<group>"; };
EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentLabelAttributeModel.swift; sourceTree = "<group>"; }; EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentLabelAttributeModel.swift; sourceTree = "<group>"; };
EAF978202A99035B00C2FEA9 /* Enabling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Enabling.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -487,10 +491,12 @@
EAF1FE9829D4850E00101452 /* Clickable.swift */, EAF1FE9829D4850E00101452 /* Clickable.swift */,
EAA5EEDF28F49DB3003B3210 /* Colorable.swift */, EAA5EEDF28F49DB3003B3210 /* Colorable.swift */,
EA3361A9288B25E40071C351 /* Disabling.swift */, EA3361A9288B25E40071C351 /* Disabling.swift */,
EAF978202A99035B00C2FEA9 /* Enabling.swift */,
EA5E305929510F8B0082B959 /* EnumSubset.swift */, EA5E305929510F8B0082B959 /* EnumSubset.swift */,
EAF7F0A1289AFB3900B287F5 /* Errorable.swift */, EAF7F0A1289AFB3900B287F5 /* Errorable.swift */,
EA3361AE288B26310071C351 /* FormFieldable.swift */, EA3361AE288B26310071C351 /* FormFieldable.swift */,
EA33624628931B050071C351 /* Initable.swift */, EA33624628931B050071C351 /* Initable.swift */,
EA471F392A95587500CE9E58 /* LayoutConstraintable.swift */,
EA985C7C297DAED300F2FF2E /* Primitive.swift */, EA985C7C297DAED300F2FF2E /* Primitive.swift */,
EAF7F0A5289B0CE000B287F5 /* Resetable.swift */, EAF7F0A5289B0CE000B287F5 /* Resetable.swift */,
EA3361C8289054C50071C351 /* Surfaceable.swift */, EA3361C8289054C50071C351 /* Surfaceable.swift */,
@ -963,6 +969,7 @@
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */, EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */, EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */, EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
EA471F3A2A95587500CE9E58 /* LayoutConstraintable.swift in Sources */,
EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */, EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */,
EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */, EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */,
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */, EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */,
@ -977,6 +984,7 @@
EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */, EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */,
EA513A952A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift in Sources */, EA513A952A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift in Sources */,
44604AD729CE196600E62B51 /* Line.swift in Sources */, 44604AD729CE196600E62B51 /* Line.swift in Sources */,
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */, EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */, EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */,
@ -1167,7 +1175,7 @@
BUILD_LIBRARY_FOR_DISTRIBUTION = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 39; CURRENT_PROJECT_VERSION = 40;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
@ -1204,7 +1212,7 @@
BUILD_LIBRARY_FOR_DISTRIBUTION = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 39; CURRENT_PROJECT_VERSION = 40;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -9,6 +9,14 @@ import Foundation
import UIKit 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 /// Bundle Manager keeps all bundles together for ease of use for searching within any of them for a specific asset
public class BundleManager { public class BundleManager {
public static var shared = BundleManager() public static var shared = BundleManager()

View File

@ -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. ///Meant to be used with any object that implements Surfaceable and Disabling. More than likely this is any View.
public class ViewColorConfiguration: KeyColorConfigurable { public class ViewColorConfiguration: KeyColorConfigurable {
public typealias KeyType = Bool public typealias KeyType = Bool
public typealias ObjectType = Surfaceable & Disabling public typealias ObjectType = Surfaceable & Enabling
public var keyColors: [KeyColorConfiguration<KeyType>] = [] public var keyColors: [KeyColorConfiguration<KeyType>] = []
public required init() { } public required init() { }
@ -161,7 +161,7 @@ public class ViewColorConfiguration: KeyColorConfigurable {
/// - Parameter object: Object that implements Surfaceable and Disabling /// - Parameter object: Object that implements Surfaceable and Disabling
/// - Returns: UIColor correspoding to either true/false for the disabled state and surface /// - Returns: UIColor correspoding to either true/false for the disabled state and surface
public func getColor(_ object: ObjectType) -> UIColor { 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) return keyColor.surfaceConfig.getColor(object)
} else { } else {
return .clear //default return .clear //default

View File

@ -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 /// Current Surface and this is used to pass down to child objects that implement Surfacable
open var surface: Surface = .light { didSet { setNeedsUpdate() } } 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. /// Whether the Control is selected or not.
open override var isSelected: Bool { didSet { setNeedsUpdate() } } 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 open var touchUpInsideCount: Int = 0
var isHighlightAnimating = false var isHighlightAnimating = false
@ -60,7 +53,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
/// Whether the Control is highlighted or not.. /// Whether the Control is highlighted or not..
open override var isHighlighted: Bool { open override var isHighlighted: Bool {
didSet { didSet {
if isHighlightAnimating == false && touchUpInsideCount > 0 { if canHighlight && isHighlightAnimating == false && touchUpInsideCount > 0 {
isHighlightAnimating = true isHighlightAnimating = true
UIView.animate(withDuration: 0.1, animations: { [weak self] in UIView.animate(withDuration: 0.1, animations: { [weak self] in
self?.setNeedsUpdate() self?.setNeedsUpdate()
@ -76,7 +69,12 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
} }
/// Whether the Control is enabled or not. /// 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 // MARK: - Initializers
@ -137,7 +135,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
open func reset() { open func reset() {
backgroundColor = .clear backgroundColor = .clear
surface = .light surface = .light
disabled = false isEnabled = true
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -27,13 +27,11 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
} }
} }
} }
/// Whether this object is disabled or not /// Whether this object is enabled or not
override open var disabled: Bool { override open var isEnabled: Bool {
didSet { didSet {
selectorViews.forEach { handler in selectorViews.forEach { $0.isEnabled = isEnabled }
handler.disabled = disabled
}
} }
} }

View File

@ -33,7 +33,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private var shouldShowError: Bool { private var shouldShowError: Bool {
guard showError && !disabled && errorText?.isEmpty == false else { return false } guard showError && isEnabled && errorText?.isEmpty == false else { return false }
return true return true
} }
@ -191,7 +191,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
selectorView.showError = showError selectorView.showError = showError
selectorView.isSelected = isSelected selectorView.isSelected = isSelected
selectorView.isHighlighted = isHighlighted selectorView.isHighlighted = isHighlighted
selectorView.disabled = disabled selectorView.isEnabled = isEnabled
selectorView.surface = surface selectorView.surface = surface
} }
@ -237,7 +237,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
//top label //top label
if let labelText { if let labelText {
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
label.attributes = labelTextAttributes label.attributes = labelTextAttributes
label.text = labelText label.text = labelText
label.isHidden = false label.isHidden = false
@ -252,7 +252,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
if let childText { if let childText {
childLabel.text = childText childLabel.text = childText
childLabel.surface = surface childLabel.surface = surface
childLabel.disabled = disabled childLabel.isEnabled = isEnabled
childLabel.attributes = childTextAttributes childLabel.attributes = childTextAttributes
childLabel.isHidden = false childLabel.isHidden = false
@ -276,7 +276,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
if let errorText, shouldShowError { if let errorText, shouldShowError {
errorLabel.text = errorText errorLabel.text = errorText
errorLabel.surface = surface errorLabel.surface = surface
errorLabel.disabled = disabled errorLabel.isEnabled = isEnabled
mainStackView.spacing = 8 mainStackView.spacing = 8
errorLabel.isHidden = false errorLabel.isHidden = false
} else { } else {

View File

@ -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 /// Current Surface and this is used to pass down to child objects that implement Surfacable
open var surface: Surface = .light { didSet { setNeedsUpdate() } } 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. /// 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 // MARK: - Initializers
@ -101,7 +91,7 @@ open class View: UIView, ViewProtocol, UserInfoable {
open func reset() { open func reset() {
backgroundColor = .clear backgroundColor = .clear
surface = .light surface = .light
disabled = false isEnabled = true
} }
} }

View File

@ -27,9 +27,11 @@ open class Badge: View {
/// Label used to render text /// Label used to render text
open var label = Label().with { open var label = Label().with {
$0.setContentCompressionResistancePriority(.required, for: .vertical)
$0.adjustsFontSizeToFitWidth = false
$0.lineBreakMode = .byTruncatingTail $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.textPosition = .left
$0.textStyle = .boldBodySmall $0.textStyle = .boldBodySmall
} }
@ -37,7 +39,7 @@ open class Badge: View {
/// This will render the badges fill color based on the available options. /// 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. /// 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() }} open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }}
/// The text that will be shown in the label. /// The text that will be shown in the label.
open var text: String = "" { didSet { setNeedsUpdate() }} 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. /// 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() }} open var numberOfLines: Int = 1 { didSet { setNeedsUpdate() }}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Constraints // MARK: - Constraints
//-------------------------------------------------- //--------------------------------------------------
private var maxWidthConstraint: NSLayoutConstraint? 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 // 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. /// ColorConfiguration that is mapped to the 'fillColor' for the surface.
private var backgroundColorConfiguration: AnyColorable = { private var backgroundColorConfiguration: AnyColorable = {
@ -96,23 +109,23 @@ open class Badge: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
open override func setup() { open override func setup() {
super.setup() super.setup()
accessibilityElements = [label] accessibilityElements = [label]
layer.cornerRadius = 2 layer.cornerRadius = 2
addSubview(label) 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) label
minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23) .pinTop(labelInset.top)
minWidthConstraint?.isActive = true .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. /// Resets to default settings.
@ -136,20 +149,14 @@ open class Badge: View {
super.updateView() super.updateView()
updateTextColorConfig() updateTextColorConfig()
updateMaxWidth()
backgroundColor = backgroundColorConfiguration.getColor(self)
backgroundColor = backgroundColorConfiguration.getColor(self)
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
label.numberOfLines = numberOfLines label.numberOfLines = numberOfLines
label.text = text label.text = text
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
if let maxWidth = maxWidth, let minWidth = minWidthConstraint?.constant, maxWidth > minWidth {
maxWidthConstraint?.constant = maxWidth
maxWidthConstraint?.isActive = true
} else {
maxWidthConstraint?.isActive = false
}
} }
} }

View File

@ -258,19 +258,12 @@ open class BadgeIndicator: View {
badgeView.addSubview(label) badgeView.addSubview(label)
accessibilityElements = [label] accessibilityElements = [label]
heightConstraint = badgeView.heightAnchor.constraint(greaterThanOrEqualToConstant: badgeSize) heightConstraint = badgeView.heightGreaterThanEqualTo(constant: badgeSize)
heightConstraint?.isActive = true widthConstraint = badgeView.widthGreaterThanEqualTo(constant: badgeSize)
widthConstraint = badgeView.widthAnchor.constraint(greaterThanOrEqualToConstant: badgeSize)
widthConstraint?.isActive = true
//we are insetting the padding to compensate for the border //we are insetting the padding to compensate for the border
NSLayoutConstraint.activate([ badgeView.pinToSuperView(.init(top: borderWidth, left: borderWidth, bottom: borderWidth, right: borderWidth))
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)])
labelContraints.topConstraint = label.pinTopGreaterThanOrEqualTo(anchor: badgeView.topAnchor) labelContraints.topConstraint = label.pinTopGreaterThanOrEqualTo(anchor: badgeView.topAnchor)
labelContraints.bottomConstraint = label.pinBottomGreaterThanOrEqualTo(anchor: badgeView.bottomAnchor) labelContraints.bottomConstraint = label.pinBottomGreaterThanOrEqualTo(anchor: badgeView.bottomAnchor)
labelContraints.leadingConstraint = label.pinLeadingGreaterThanOrEqualTo(anchor: badgeView.leadingAnchor) labelContraints.leadingConstraint = label.pinLeadingGreaterThanOrEqualTo(anchor: badgeView.leadingAnchor)
@ -348,7 +341,7 @@ open class BadgeIndicator: View {
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
label.text = getText() label.text = getText()
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
label.sizeToFit() label.sizeToFit()
setNeedsLayout() setNeedsLayout()
layoutIfNeeded() layoutIfNeeded()

View File

@ -22,9 +22,6 @@ open class Button: ButtonBase, Useable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private var minWidthConstraint: NSLayoutConstraint?
private var widthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
private var initialSetupPerformed = false private var initialSetupPerformed = false
//-------------------------------------------------- //--------------------------------------------------
@ -36,7 +33,18 @@ open class Button: ButtonBase, Useable {
open var size: ButtonSize = .large { didSet { setNeedsUpdate() }} 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 { open override var textColor: UIColor {
textColorConfiguration.getColor(self) textColorConfiguration.getColor(self)
@ -120,14 +128,6 @@ open class Button: ButtonBase, Useable {
super.setup() super.setup()
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .button 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. /// Resets to default settings.
@ -145,7 +145,12 @@ open class Button: ButtonBase, Useable {
// MARK: - Overrides // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
open override var intrinsicContentSize: CGSize { 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) 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 bgColor = backgroundColorConfiguration.getColor(self)
let borderColor = borderColorConfiguration.getColor(self) let borderColor = borderColorConfiguration.getColor(self)
let borderWidth = use == .secondary ? VDSFormControls.widthBorder : 0.0 let borderWidth = use == .secondary ? VDSFormControls.widthBorder : 0.0
let buttonHeight = size.height
let cornerRadius = size.cornerRadius let cornerRadius = size.cornerRadius
let minWidth = size.minimumWidth
let edgeInsets = size.edgeInsets let edgeInsets = size.edgeInsets
backgroundColor = bgColor backgroundColor = bgColor
@ -166,18 +169,8 @@ open class Button: ButtonBase, Useable {
layer.cornerRadius = cornerRadius layer.cornerRadius = cornerRadius
layer.borderWidth = borderWidth layer.borderWidth = borderWidth
contentEdgeInsets = edgeInsets contentEdgeInsets = edgeInsets
minWidthConstraint?.constant = minWidth invalidateIntrinsicContentSize()
heightConstraint?.constant = buttonHeight
if let width, width > minWidth {
widthConstraint?.constant = width
widthConstraint?.isActive = true
minWidthConstraint?.isActive = false
} else {
widthConstraint?.isActive = false
minWidthConstraint?.isActive = true
}
} }
} }

View File

@ -11,7 +11,7 @@ import VDSColorTokens
import VDSFormControlsTokens import VDSFormControlsTokens
import Combine import Combine
public protocol Buttonable: UIControl, Surfaceable, Disabling { public protocol Buttonable: UIControl, Surfaceable, Enabling {
var availableSizes: [ButtonSize] { get } var availableSizes: [ButtonSize] { get }
var text: String? { get set } var text: String? { get set }
var intrinsicContentSize: CGSize { get } 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. /// 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 } open var textStyle: TextStyle { .defaultStyle }
@ -144,7 +134,7 @@ open class ButtonBase: UIButton, Buttonable, ViewProtocol, UserInfoable, Clickab
open func reset() { open func reset() {
shouldUpdateView = false shouldUpdateView = false
surface = .light surface = .light
disabled = false isEnabled = true
text = nil text = nil
accessibilityCustomActions = [] accessibilityCustomActions = []
shouldUpdateView = true shouldUpdateView = true

View File

@ -93,13 +93,10 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Overrides // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
/// Whether this object is disabled or not /// Whether this object is enabled or not
override open var disabled: Bool { override open var isEnabled: Bool {
didSet { didSet {
buttons.forEach { button in buttons.forEach { $0.isEnabled = isEnabled }
var b = button
b.disabled = disabled
}
} }
} }
@ -130,12 +127,13 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Functions // MARK: - Public Functions
//-------------------------------------------------- //--------------------------------------------------
open override func setup() { open override func setup() {
super.setup() super.setup()
addSubview(collectionView) addSubview(collectionView)
collectionView.pinToSuperView() collectionView.pinToSuperView()
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Overrides // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
@ -150,11 +148,12 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
open override func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
// Accounts for any collection size changes // Accounts for any collection size changes
DispatchQueue.main.async { DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.collectionView.collectionViewLayout.invalidateLayout() self.collectionView.collectionViewLayout.invalidateLayout()
} }
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - UICollectionViewDataSource // MARK: - UICollectionViewDataSource
//-------------------------------------------------- //--------------------------------------------------
@ -195,5 +194,4 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega
public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable { public func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable {
buttons[indexPath.row] buttons[indexPath.row]
} }
} }

View File

@ -18,6 +18,10 @@ open class TextLink: ButtonBase {
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private var lineHeightConstraint: NSLayoutConstraint? private var lineHeightConstraint: NSLayoutConstraint?
private var line = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
@ -64,10 +68,6 @@ open class TextLink: ButtonBase {
super.init(coder: coder) super.init(coder: coder)
} }
private var line = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Functions // MARK: - Public Functions
//-------------------------------------------------- //--------------------------------------------------
@ -75,15 +75,15 @@ open class TextLink: ButtonBase {
super.setup() super.setup()
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .link accessibilityTraits = .link
if let titleLabel { if let titleLabel {
addSubview(line) addSubview(line)
line.pinLeading(titleLabel.leadingAnchor) line.pinLeading(titleLabel.leadingAnchor)
line.pinTrailing(titleLabel.trailingAnchor) line.pinTrailing(titleLabel.trailingAnchor)
line.pinTop(titleLabel.bottomAnchor) line.pinTop(titleLabel.bottomAnchor)
line.pinBottom(bottomAnchor) line.pinBottom(bottomAnchor, 0, .defaultHigh)
lineHeightConstraint = line.heightAnchor.constraint(equalToConstant: 1.0) lineHeightConstraint = line.height(constant: 1)
lineHeightConstraint?.isActive = true lineHeightConstraint?.isActive = true
titleLabel.debugBorder(show: true)
} }
} }
@ -92,7 +92,7 @@ open class TextLink: ButtonBase {
super.reset() super.reset()
shouldUpdateView = false shouldUpdateView = false
text = nil text = nil
size = .large size = .large
accessibilityCustomActions = [] accessibilityCustomActions = []
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .link accessibilityTraits = .link

View File

@ -119,7 +119,7 @@ extension TextLinkCaret {
} }
func setAttribute(on attributedString: NSMutableAttributedString) { 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) let spacer = NSAttributedString.spacer(for: spacerWidth)
guard let image = try? imageAttr.getAttachment() else { return } guard let image = try? imageAttr.getAttachment() else { return }

View File

@ -99,7 +99,7 @@ open class Checkbox: SelectorBase {
shapeLayer?.removeAllAnimations() shapeLayer?.removeAllAnimations()
if isAnimated && !disabled && !isHighlighted { if isAnimated && isEnabled && !isHighlighted {
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd") let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear)
animateStrokeEnd.duration = 0.3 animateStrokeEnd.duration = 0.3

View File

@ -40,7 +40,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase<CheckboxItem> {
if let selectorModels { if let selectorModels {
selectorViews = selectorModels.enumerated().map { index, model in selectorViews = selectorModels.enumerated().map { index, model in
return CheckboxItem().with { return CheckboxItem().with {
$0.disabled = model.disabled $0.isEnabled = !model.disabled
$0.surface = model.surface $0.surface = model.surface
$0.inputId = model.inputId $0.inputId = model.inputId
$0.value = model.value $0.value = model.value
@ -110,7 +110,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase<CheckboxItem> {
} }
extension CheckboxGroup { extension CheckboxGroup {
public struct CheckboxModel : Surfaceable, Disabling, Initable, FormFieldable, Errorable { public struct CheckboxModel : Surfaceable, Initable, FormFieldable, Errorable {
/// Whether this object is disabled or not /// Whether this object is disabled or not
public var disabled: Bool public var disabled: Bool

View File

@ -235,22 +235,17 @@ open class ButtonIcon: Control {
addSubview(icon) addSubview(icon)
//determines the height/width of the icon //determines the height/width of the icon
layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) layoutGuideWidthConstraint = iconLayoutGuide.width(constant: size.containerSize)
layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) layoutGuideHeightConstraint = iconLayoutGuide.height(constant: size.containerSize)
//pin layout guide
iconLayoutGuide.pinToSuperView()
//determines the center point of the icon //determines the center point of the icon
centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0)
centerXConstraint?.activate()
centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0)
centerYConstraint?.activate()
//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)])
} }
/// Resets to default settings. /// Resets to default settings.

View File

@ -16,8 +16,10 @@ open class Icon: View {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private var widthConstraint: NSLayoutConstraint? private var dimensions: CGSize {
private var heightConstraint: NSLayoutConstraint? guard let customSize else { return size.dimensions }
return .init(width: customSize, height: customSize)
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
@ -42,20 +44,20 @@ open class Icon: View {
//functions //functions
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
open override func setup() { open override func setup() {
super.setup() super.setup()
setContentCompressionResistancePriority(.required, for: .vertical)
setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .horizontal)
setContentHuggingPriority(.required, for: .horizontal)
addSubview(imageView) addSubview(imageView)
imageView.pinToSuperView() 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 backgroundColor = .clear
isAccessibilityElement = true isAccessibilityElement = true
@ -68,6 +70,10 @@ open class Icon: View {
color = VDSColor.paletteBlack color = VDSColor.paletteBlack
imageView.image = nil 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. /// Function used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
@ -81,17 +87,7 @@ open class Icon: View {
} else if surface == .light && color == VDSColor.paletteBlack { } else if surface == .light && color == VDSColor.paletteBlack {
imageColor = VDSColor.elementsPrimaryOnlight 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 //get the image name
//set the image //set the image
if let name, let image = getImage(for: name.rawValue) { if let name, let image = getImage(for: name.rawValue) {
@ -99,8 +95,10 @@ open class Icon: View {
} else { } else {
imageView.image = nil imageView.image = nil
} }
}
invalidateIntrinsicContentSize()
}
private func getImage(for imageName: String) -> UIImage? { private func getImage(for imageName: String) -> UIImage? {
return BundleManager.shared.image(for: imageName) return BundleManager.shared.image(for: imageName)

View File

@ -38,18 +38,17 @@ public struct ActionLabelAttribute: ActionLabelAttributeModel {
public var length: Int public var length: Int
public var shouldUnderline: Bool public var shouldUnderline: Bool
public var accessibleText: String? public var accessibleText: String?
public var action: PassthroughSubject<Void, Never> public var action = PassthroughSubject<Void, Never>()
public var subscriber: AnyCancellable? public var subscriber: AnyCancellable?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // MARK: - Initializer
//-------------------------------------------------- //--------------------------------------------------
public init(location: Int, length: Int, shouldUnderline: Bool = true, accessibleText: String? = nil, action: PassthroughSubject<Void, Never> = .init() ) { public init(location: Int, length: Int, shouldUnderline: Bool = true, accessibleText: String? = nil) {
self.location = location self.location = location
self.length = length self.length = length
self.shouldUnderline = shouldUnderline self.shouldUnderline = shouldUnderline
self.accessibleText = accessibleText self.accessibleText = accessibleText
self.action = action
} }
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
@ -67,3 +66,19 @@ public struct ActionLabelAttribute: ActionLabelAttributeModel {
extension NSAttributedString.Key { extension NSAttributedString.Key {
public static let action = NSAttributedString.Key(rawValue: "action") 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)
}
}

View File

@ -28,7 +28,8 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel {
public var image: UIImage? public var image: UIImage?
public var frame: CGRect? public var frame: CGRect?
public var tintColor: UIColor? public var tintColor: UIColor?
public var accessibleText: String?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Equatable // MARK: - Equatable
//-------------------------------------------------- //--------------------------------------------------
@ -40,11 +41,27 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel {
return id == equatable.id && range == equatable.range && imageName == equatable.imageName 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 // MARK: - Private Functions
//-------------------------------------------------- //--------------------------------------------------
private func imageAttachment(image: UIImage) -> NSTextAttachment { private func imageAttachment(image: UIImage) -> NSTextAttachment {
let attachment = 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 attachment.image = tintColor != nil ? image.withTintColor(tintColor!) : image
if let frame { if let frame {
attachment.bounds = frame attachment.bounds = frame

View File

@ -68,9 +68,8 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
addHandler(on: attributedString) addHandler(on: attributedString)
} }
public init(id: UUID = UUID(), action: PassthroughSubject<Void, Never> = PassthroughSubject<Void, Never>(), 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.id = id
self.action = action
self.subscriber = subscriber self.subscriber = subscriber
self.surface = surface self.surface = surface
self.accessibleText = accessibleText self.accessibleText = accessibleText

View File

@ -44,25 +44,19 @@ open class Label: UILabel, ViewProtocol, UserInfoable {
open var userInfo = [String: Primitive]() open var userInfo = [String: Primitive]()
open override var numberOfLines: Int { didSet { setNeedsUpdate() }}
open override var lineBreakMode: NSLineBreakMode { didSet { setNeedsUpdate() }}
override open var text: String? { override open var text: String? {
didSet { didSet {
attributes = nil attributes = nil
setNeedsUpdate() 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. /// 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 // MARK: - Configuration Properties
@ -119,7 +113,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable {
open func reset() { open func reset() {
shouldUpdateView = false shouldUpdateView = false
surface = .light surface = .light
disabled = false isEnabled = true
attributes = nil attributes = nil
textStyle = .defaultStyle textStyle = .defaultStyle
textPosition = .left textPosition = .left

View File

@ -19,15 +19,16 @@ open class Line: View {
case primary, secondary case primary, secondary
} }
public enum Orientation: String, CaseIterable {
case horizontal, vertical
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
open var lineView = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
open var style: Style = .primary { didSet { setNeedsUpdate() } } open var style: Style = .primary { didSet { setNeedsUpdate() } }
open var orientation: Orientation = .horizontal { didSet { setNeedsUpdate() } }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Configuration // MARK: - Configuration
//-------------------------------------------------- //--------------------------------------------------
@ -37,29 +38,37 @@ open class Line: View {
config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary) config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary)
return config.eraseToAnyColorable() return config.eraseToAnyColorable()
}() }()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
open override func setup() { open override var intrinsicContentSize: CGSize {
super.setup() if orientation == .vertical {
return .init(width: 1, height: bounds.height)
addSubview(lineView) } else {
lineView.height(1) return .init(width: bounds.width, height: 1)
lineView.pinToSuperView() }
} }
/// Resets to default settings. /// Resets to default settings.
open override func reset() { open override func reset() {
super.reset() super.reset()
style = .primary 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. /// Function used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
lineView.backgroundColor = lineViewColorConfiguration.getColor(self) backgroundColor = lineViewColorConfiguration.getColor(self)
invalidateIntrinsicContentSize()
} }
} }

View File

@ -27,7 +27,14 @@ open class Loader: View {
open var isActive: Bool = true { didSet { setNeedsUpdate() } } open var isActive: Bool = true { didSet { setNeedsUpdate() } }
/// The Int used to determine the height and width of the Loader /// 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 // MARK: - Lifecycle
@ -36,13 +43,15 @@ open class Loader: View {
super.setup() super.setup()
addSubview(icon) addSubview(icon)
icon
.pinTopGreaterThanOrEqualTo()
.pinLeadingGreaterThanOrEqualTo()
.pinTrailingLessThanOrEqualTo()
.pinBottomLessThanOrEqualTo()
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
icon.centerXAnchor.constraint(equalTo: centerXAnchor), icon.centerXAnchor.constraint(equalTo: centerXAnchor),
icon.centerYAnchor.constraint(equalTo: centerYAnchor), 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)
]) ])
} }

View File

@ -43,7 +43,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase<RadioBoxItem> {
$0.subTextAttributes = model.subTextAttributes $0.subTextAttributes = model.subTextAttributes
$0.subTextRight = model.subText $0.subTextRight = model.subText
$0.subTextRightAttributes = model.subTextAttributes $0.subTextRightAttributes = model.subTextAttributes
$0.disabled = model.disabled $0.isEnabled = !model.disabled
$0.inputId = model.inputId $0.inputId = model.inputId
$0.isSelected = model.selected $0.isSelected = model.selected
} }
@ -106,7 +106,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase<RadioBoxItem> {
} }
extension RadioBoxGroup { extension RadioBoxGroup {
public struct RadioBoxModel: Surfaceable, Initable, Disabling, FormFieldable { public struct RadioBoxModel: Surfaceable, Initable, FormFieldable {
/// Whether this object is disabled or not /// Whether this object is disabled or not
public var disabled: Bool public var disabled: Bool
/// Current Surface and this is used to pass down to child objects that implement Surfacable /// Current Surface and this is used to pass down to child objects that implement Surfacable

View File

@ -187,14 +187,14 @@ open class RadioBoxItem: Control, Changeable {
//text label //text label
textLabel.text = text textLabel.text = text
textLabel.surface = surface textLabel.surface = surface
textLabel.disabled = disabled textLabel.isEnabled = isEnabled
textLabel.attributes = textAttributes textLabel.attributes = textAttributes
//subText label //subText label
if let subText { if let subText {
subTextLabel.text = subText subTextLabel.text = subText
subTextLabel.surface = surface subTextLabel.surface = surface
subTextLabel.disabled = disabled subTextLabel.isEnabled = isEnabled
subTextLabel.attributes = subTextAttributes subTextLabel.attributes = subTextAttributes
subTextLabel.isHidden = false subTextLabel.isHidden = false
@ -209,7 +209,7 @@ open class RadioBoxItem: Control, Changeable {
if let subTextRight { if let subTextRight {
subTextRightLabel.text = subTextRight subTextRightLabel.text = subTextRight
subTextRightLabel.surface = surface subTextRightLabel.surface = surface
subTextRightLabel.disabled = disabled subTextRightLabel.isEnabled = isEnabled
subTextRightLabel.attributes = subTextRightAttributes subTextRightLabel.attributes = subTextRightAttributes
subTextRightLabel.isHidden = false subTextRightLabel.isHidden = false

View File

@ -35,7 +35,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase<RadioButtonItem> {
if let selectorModels { if let selectorModels {
selectorViews = selectorModels.enumerated().map { index, model in selectorViews = selectorModels.enumerated().map { index, model in
return RadioButtonItem().with { return RadioButtonItem().with {
$0.disabled = model.disabled $0.isEnabled = !model.disabled
$0.surface = model.surface $0.surface = model.surface
$0.inputId = model.inputId $0.inputId = model.inputId
$0.value = model.value $0.value = model.value
@ -114,7 +114,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase<RadioButtonItem> {
} }
extension RadioButtonGroup { extension RadioButtonGroup {
public struct RadioButtonModel: Surfaceable, Disabling, Initable, FormFieldable, Errorable { public struct RadioButtonModel: Surfaceable, Initable, FormFieldable, Errorable {
/// Whether this object is disabled or not /// Whether this object is disabled or not
public var disabled: Bool public var disabled: Bool

View File

@ -176,13 +176,13 @@ open class RadioSwatch: Control {
var fillColorBackground: UIColor = .clear var fillColorBackground: UIColor = .clear
if let fillImage { if let fillImage {
fillView.image = disabled ? fillImage.image(alpha: disabledAlpha) : fillImage fillView.image = !isEnabled ? fillImage.image(alpha: disabledAlpha) : fillImage
} else { } else {
fillView.image = nil fillView.image = nil
if let primary = primaryColor, let secondary = secondaryColor { if let primary = primaryColor, let secondary = secondaryColor {
let firstColor = disabled ? primary.withAlphaComponent(disabledAlpha) : primary let firstColor = !isEnabled ? primary.withAlphaComponent(disabledAlpha) : primary
let secondColor = disabled ? secondary.withAlphaComponent(disabledAlpha) : secondary let secondColor = !isEnabled ? secondary.withAlphaComponent(disabledAlpha) : secondary
let gradient = CAGradientLayer() let gradient = CAGradientLayer()
gradientLayer = gradient gradientLayer = gradient
gradient.frame = fillView.bounds 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.borderColor = fillBorderColor.cgColor
fillView.layer.cornerRadius = fillView.bounds.width * 0.5 fillView.layer.cornerRadius = fillView.bounds.width * 0.5
fillView.layer.borderWidth = selectorBorderWidth fillView.layer.borderWidth = selectorBorderWidth

View File

@ -32,7 +32,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICo
$0.primaryColor = model.primaryColor $0.primaryColor = model.primaryColor
$0.secondaryColor = model.secondaryColor $0.secondaryColor = model.secondaryColor
$0.strikethrough = model.strikethrough $0.strikethrough = model.strikethrough
$0.disabled = model.disabled $0.isEnabled = !model.disabled
$0.surface = model.surface $0.surface = model.surface
$0.inputId = model.inputId $0.inputId = model.inputId
$0.value = model.value $0.value = model.value
@ -71,15 +71,15 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICo
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Overrides // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
/// Whether this object is disabled or not /// Whether this object is disabled or not
override public var disabled: Bool { override public var isEnabled: Bool {
didSet { didSet {
for selector in selectorViews { selectorViews.forEach { $0.isEnabled = isEnabled }
selector.disabled = disabled
}
collectionView.reloadData() collectionView.reloadData()
} }
} }
/// Current Surface and this is used to pass down to child objects that implement Surfacable /// Current Surface and this is used to pass down to child objects that implement Surfacable
override public var surface: Surface { override public var surface: Surface {
didSet { didSet {
@ -132,7 +132,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICo
label.textStyle = .bodySmall label.textStyle = .bodySmall
label.text = selectedHandler?.text ?? " " label.text = selectedHandler?.text ?? " "
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
collectionView.reloadData() collectionView.reloadData()
} }
@ -151,7 +151,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICo
// MARK: - UICollectionViewDelegate // MARK: - UICollectionViewDelegate
//-------------------------------------------------- //--------------------------------------------------
open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { 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) { open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
@ -193,7 +193,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICo
} }
extension RadioSwatchGroup { extension RadioSwatchGroup {
public struct RadioSwatchModel: Surfaceable, Disabling, Initable { public struct RadioSwatchModel: Surfaceable, Initable {
/// Whether this object is disabled or not /// Whether this object is disabled or not
public var disabled: Bool = false public var disabled: Bool = false
/// Current Surface and this is used to pass down to child objects that implement Surfacable /// Current Surface and this is used to pass down to child objects that implement Surfacable

View File

@ -95,12 +95,11 @@ extension Tabs {
private let layoutGuide = UILayoutGuide() private let layoutGuide = UILayoutGuide()
private var widthConstraint: NSLayoutConstraint? { private func updateWidth() {
if let width, orientation == .vertical { labelWidthConstraint?.isActive = false
return layoutGuide.widthAnchor.constraint(equalToConstant: width) guard let width, width > minWidth else { return }
} else { labelWidthConstraint?.constant = width
return layoutGuide.widthAnchor.constraint(greaterThanOrEqualToConstant: minWidth) labelWidthConstraint?.isActive = true
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -124,27 +123,26 @@ extension Tabs {
open override func setup() { open override func setup() {
super.setup() super.setup()
canHighlight = false
addLayoutGuide(layoutGuide) addLayoutGuide(layoutGuide)
addSubview(label) addSubview(label)
accessibilityTraits = .button accessibilityTraits = .button
isAccessibilityElement = true isAccessibilityElement = true
//activate the constraints //pin layoutguide
NSLayoutConstraint.activate([layoutGuide.topAnchor.constraint(equalTo: topAnchor), layoutGuide.pinToSuperView()
layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor),
layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor),
layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
//pin trailing
label.pinTrailing(layoutGuide.trailingAnchor) label.pinTrailing(layoutGuide.trailingAnchor)
labelTopConstraint = label.topAnchor.constraint(equalTo: layoutGuide.topAnchor) //setup constraints
labelTopConstraint?.isActive = true labelWidthConstraint = layoutGuide.width(constant: 0).with { $0.isActive = false }
layoutGuide.widthGreaterThanEqualTo(minWidth)
labelBottomConstraint = label.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor) labelTopConstraint = label.pinTop(anchor: layoutGuide.topAnchor)
labelBottomConstraint?.isActive = true labelLeadingConstraint = label.pinLeading(anchor: layoutGuide.leadingAnchor)
labelBottomConstraint = label.pinBottom(anchor: layoutGuide.bottomAnchor, priority: .defaultHigh)
labelLeadingConstraint = label.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
labelLeadingConstraint?.isActive = true
} }
/// Function used to make changes to the View based off a change events or from local properties. /// 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)" accessibilityIdentifier = "VDSTab:\(text)"
//constaints //constaints
labelWidthConstraint?.isActive = false updateWidth()
labelWidthConstraint = widthConstraint
labelWidthConstraint?.isActive = true
labelLeadingConstraint?.constant = leadingSpace labelLeadingConstraint?.constant = leadingSpace
labelTopConstraint?.constant = otherSpace labelTopConstraint?.constant = otherSpace
labelBottomConstraint?.constant = -otherSpace labelBottomConstraint?.constant = -otherSpace
@ -169,7 +165,6 @@ extension Tabs {
label.textStyle = textStyle label.textStyle = textStyle
label.textPosition = textPosition label.textPosition = textPosition
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
setNeedsLayout() setNeedsLayout()
layoutIfNeeded() layoutIfNeeded()

View File

@ -144,6 +144,10 @@ open class Tabs: View {
orientation == .horizontal && fillContainer ? .center : .left orientation == .horizontal && fillContainer ? .center : .left
} }
private var applyOverflow: Bool {
orientation == .horizontal && overflow == .scroll && !fillContainer
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
@ -187,20 +191,20 @@ open class Tabs: View {
contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
borderlineViewWidthConstraint = borderlineView.widthAnchor.constraint(equalToConstant: 0) borderlineViewWidthConstraint = borderlineView.width(constant: 0)
borderlineViewHeightConstraint = borderlineView.heightAnchor.constraint(equalToConstant: 0) borderlineViewHeightConstraint = borderlineView.height(constant: 0)
borderlineViewLeadingConstraint = borderlineView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor) borderlineViewLeadingConstraint = borderlineView.pinLeading(anchor: contentView.leadingAnchor)
borderlineViewTrailingConstraint = borderlineView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) borderlineViewTrailingConstraint = borderlineView.pinTrailing(anchor: contentView.trailingAnchor)
borderlineViewTopConstraint = borderlineView.topAnchor.constraint(equalTo: contentView.topAnchor) borderlineViewTopConstraint = borderlineView.pinTop(anchor: contentView.topAnchor)
borderlineViewBottomConstraint = borderlineView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) borderlineViewBottomConstraint = borderlineView.pinBottom(anchor: contentView.bottomAnchor)
} }
/// Function used to make changes to the View based off a change events or from local properties. /// Function used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
updateStackView() updateStackView()
updateTabs() updateTabs()
updateContentView() updateContentView()
@ -258,7 +262,9 @@ open class Tabs: View {
/// Updates the Tab individual views from local properties. /// Updates the Tab individual views from local properties.
private func updateTabs() { private func updateTabs() {
let numberOfLines = applyOverflow ? 1 : 0
for (index, tabItem) in tabViews.enumerated() { for (index, tabItem) in tabViews.enumerated() {
tabItem.label.numberOfLines = numberOfLines
tabItem.size = size tabItem.size = size
tabItem.isSelected = selectedIndex == index tabItem.isSelected = selectedIndex == index
tabItem.index = index tabItem.index = index
@ -277,10 +283,10 @@ open class Tabs: View {
contentViewWidthConstraint?.isActive = false contentViewWidthConstraint?.isActive = false
// Apply overflow // Apply overflow
if orientation == .horizontal && overflow == .scroll && !fillContainer { if applyOverflow {
let contentWidth = tabStackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
contentViewWidthConstraint = nil 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 { } else {
contentViewWidthConstraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor) contentViewWidthConstraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
scrollView.contentSize = bounds.size scrollView.contentSize = bounds.size
@ -294,6 +300,11 @@ open class Tabs: View {
scrollToSelectedIndex(animated: true) scrollToSelectedIndex(animated: true)
} }
open override func layoutSubviews() {
super.layoutSubviews()
updateContentView()
}
//update layout for borderline //update layout for borderline
private func updateBorderline() { private func updateBorderline() {
//borderLine //borderLine

View File

@ -132,12 +132,7 @@ open class TabsContainer: View {
stackView.addArrangedSubview(tabMenu) stackView.addArrangedSubview(tabMenu)
stackView.addArrangedSubview(contentView) stackView.addArrangedSubview(contentView)
NSLayoutConstraint.activate([ tabMenuLayoutGuide.pinToSuperView()
tabMenuLayoutGuide.topAnchor.constraint(equalTo: topAnchor),
tabMenuLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor),
tabMenuLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor),
tabMenuLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)
])
} }
/// Function used to make changes to the View based off a change events or from local properties. /// 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 contentViewWidthConstraint?.isActive = true
tabMenu.surface = surface tabMenu.surface = surface
tabMenu.disabled = disabled tabMenu.isEnabled = isEnabled
tabMenu.orientation = orientation tabMenu.orientation = orientation
tabMenu.borderLine = borderLine tabMenu.borderLine = borderLine
tabMenu.fillContainer = fillContainer tabMenu.fillContainer = fillContainer

View File

@ -283,7 +283,7 @@ open class EntryField: Control, Changeable {
//dealing with the "Optional" addition to the text //dealing with the "Optional" addition to the text
if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") { if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") {
if !disabled { if isEnabled {
let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2, let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2,
length: 8, length: 8,
color: VDSColor.elementsSecondaryOnlight) color: VDSColor.elementsSecondaryOnlight)
@ -301,20 +301,19 @@ open class EntryField: Control, Changeable {
titleLabel.text = updatedLabelText titleLabel.text = updatedLabelText
titleLabel.attributes = attributes titleLabel.attributes = attributes
titleLabel.surface = surface titleLabel.surface = surface
titleLabel.disabled = disabled titleLabel.isEnabled = isEnabled
} }
open func updateErrorLabel(){ open func updateErrorLabel(){
if showError, let errorText { if showError, let errorText {
errorLabel.text = errorText errorLabel.text = errorText
errorLabel.surface = surface errorLabel.surface = surface
errorLabel.disabled = disabled errorLabel.isEnabled = isEnabled
errorLabel.isHidden = false errorLabel.isHidden = false
icon.name = .error icon.name = .error
icon.color = VDSColor.paletteBlack icon.color = VDSColor.paletteBlack
icon.surface = surface icon.surface = surface
icon.isHidden = disabled icon.isHidden = !isEnabled
} else { } else {
icon.isHidden = true icon.isHidden = true
errorLabel.isHidden = true errorLabel.isHidden = true
@ -326,7 +325,7 @@ open class EntryField: Control, Changeable {
if let helperText { if let helperText {
helperLabel.text = helperText helperLabel.text = helperText
helperLabel.surface = surface helperLabel.surface = surface
helperLabel.disabled = disabled helperLabel.isEnabled = isEnabled
helperLabel.isHidden = false helperLabel.isHidden = false
} else { } else {
helperLabel.isHidden = true helperLabel.isHidden = true

View File

@ -165,7 +165,7 @@ open class InputField: EntryField, UITextFieldDelegate {
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
textField.isEnabled = !disabled textField.isEnabled = isEnabled
textField.textColor = textFieldTextColorConfiguration.getColor(self) textField.textColor = textFieldTextColorConfiguration.getColor(self)
//show error or success //show error or success
@ -175,13 +175,13 @@ open class InputField: EntryField, UITextFieldDelegate {
} else if showSuccess, let successText { } else if showSuccess, let successText {
successLabel.text = successText successLabel.text = successText
successLabel.surface = surface successLabel.surface = surface
successLabel.disabled = disabled successLabel.isEnabled = isEnabled
successLabel.isHidden = false successLabel.isHidden = false
errorLabel.isHidden = true errorLabel.isHidden = true
icon.name = .checkmarkAlt icon.name = .checkmarkAlt
icon.color = VDSColor.paletteBlack icon.color = VDSColor.paletteBlack
icon.surface = surface icon.surface = surface
icon.isHidden = disabled icon.isHidden = !isEnabled
} else { } else {
icon.isHidden = true icon.isHidden = true
successLabel.isHidden = true successLabel.isHidden = true

View File

@ -95,7 +95,7 @@ open class TextArea: EntryField {
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
textView.isEditable = !disabled textView.isEditable = isEnabled
textView.textColor = textViewTextColorConfiguration.getColor(self) textView.textColor = textViewTextColorConfiguration.getColor(self)
//set the width constraints //set the width constraints

View File

@ -168,14 +168,10 @@ open class TileContainer: Control {
containerView.backgroundColor = .clear containerView.backgroundColor = .clear
containerTopConstraint = containerView.topAnchor.constraint(equalTo: topAnchor, constant: padding.value) containerTopConstraint = containerView.pinTop(anchor: topAnchor, constant: padding.value)
containerTopConstraint?.isActive = true containerBottomConstraint = containerView.pinBottom(anchor: bottomAnchor, constant: padding.value)
containerBottomConstraint = containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: padding.value) containerLeadingConstraint = containerView.pinLeading(anchor: leadingAnchor, constant: padding.value)
containerBottomConstraint?.isActive = true containerTrailingConstraint = containerView.pinTrailing(anchor: trailingAnchor, constant: padding.value)
containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.value)
containerLeadingConstraint?.isActive = true
containerTrailingConstraint = containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: padding.value)
containerTrailingConstraint?.isActive = true
highlightView.pinToSuperView() highlightView.pinToSuperView()
highlightView.isHidden = true highlightView.isHidden = true

View File

@ -43,7 +43,7 @@ open class TitleLockup: View {
private var stackView = UIStackView().with { private var stackView = UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false $0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .vertical $0.axis = .vertical
$0.distribution = .fill $0.distribution = .fillProportionally
} }
private var otherStandardStyle: OtherStandardStyle { private var otherStandardStyle: OtherStandardStyle {
@ -269,8 +269,11 @@ open class TitleLockup: View {
stackView.addArrangedSubview(subTitleLabel) stackView.addArrangedSubview(subTitleLabel)
//pin stackview to edges //pin stackview to edges
stackView.pinToSuperView() stackView
.pinTop()
.pinLeading()
.pinTrailing()
.pinBottom(0, .defaultHigh)
} }
/// Resets to default settings. /// Resets to default settings.
@ -311,7 +314,6 @@ open class TitleLockup: View {
eyebrowLabel.attributes = eyebrowModel.textAttributes eyebrowLabel.attributes = eyebrowModel.textAttributes
eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines
eyebrowLabel.surface = surface eyebrowLabel.surface = surface
//When uniform size is true //When uniform size is true
if let titleModel, isUniformSize { if let titleModel, isUniformSize {
if titleModel.isBold { if titleModel.isBold {
@ -329,8 +331,6 @@ open class TitleLockup: View {
eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration
eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular
} }
} else {
eyebrowLabel.reset()
} }
if let titleModel, !titleModel.text.isEmpty { if let titleModel, !titleModel.text.isEmpty {
@ -341,8 +341,6 @@ open class TitleLockup: View {
titleLabel.attributes = titleModel.textAttributes titleLabel.attributes = titleModel.textAttributes
titleLabel.numberOfLines = titleModel.numberOfLines titleLabel.numberOfLines = titleModel.numberOfLines
titleLabel.surface = surface titleLabel.surface = surface
} else {
titleLabel.reset()
} }
if let subTitleModel, !subTitleModel.text.isEmpty { if let subTitleModel, !subTitleModel.text.isEmpty {
@ -354,8 +352,6 @@ open class TitleLockup: View {
subTitleLabel.attributes = subTitleModel.textAttributes subTitleLabel.attributes = subTitleModel.textAttributes
subTitleLabel.numberOfLines = subTitleModel.numberOfLines subTitleLabel.numberOfLines = subTitleModel.numberOfLines
subTitleLabel.surface = surface subTitleLabel.surface = surface
} else {
subTitleLabel.reset()
} }
//if both first 2 rows not empty set spacing //if both first 2 rows not empty set spacing
@ -376,5 +372,5 @@ open class TitleLockup: View {
eyebrowLabel.isHidden = eyebrowTextIsEmpty eyebrowLabel.isHidden = eyebrowTextIsEmpty
titleLabel.isHidden = titleTextIsEmpty titleLabel.isHidden = titleTextIsEmpty
subTitleLabel.isHidden = subTitleTextIsEmpty subTitleLabel.isHidden = subTitleTextIsEmpty
} }
} }

View File

@ -86,6 +86,7 @@ open class Toggle: Control, Changeable {
open var toggleView = ToggleView().with { open var toggleView = ToggleView().with {
$0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
$0.isUserInteractionEnabled = false $0.isUserInteractionEnabled = false
$0.isAccessibilityElement = false
} }
open var label = Label().with { open var label = Label().with {
@ -140,34 +141,35 @@ open class Toggle: Control, Changeable {
open override func setup() { open override func setup() {
super.setup() super.setup()
canHighlight = false
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .button accessibilityTraits = .button
addSubview(label) addSubview(label)
addSubview(toggleView) addSubview(toggleView)
let heightEqual = heightAnchor.constraint(equalToConstant: toggleContainerSize.height) label.widthLessThanEqualTo(labelMaxWidth)
heightEqual.priority = .defaultLow
let heightGreater = heightAnchor.constraint(greaterThanOrEqualToConstant: toggleContainerSize.height)
heightGreater.priority = .defaultHigh
// Set up initial constraints for label and switch // Set up initial constraints for label and switch
toggleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true toggleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
labelConstraints = [ labelConstraints = [
heightEqual, heightGreater, height(constant: toggleContainerSize.height, priority: .defaultLow),
label.widthAnchor.constraint(lessThanOrEqualToConstant: labelMaxWidth), heightGreaterThanEqualTo(constant: toggleContainerSize.height, priority: .defaultHigh),
label.topAnchor.constraint(equalTo: topAnchor), label.topAnchor.constraint(equalTo: topAnchor),
label.bottomAnchor.constraint(equalTo: bottomAnchor), label.bottomAnchor.constraint(equalTo: bottomAnchor),
] ]
leftConstraints = [ 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 = [ 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() super.reset()
shouldUpdateView = false shouldUpdateView = false
label.reset() label.reset()
isEnabled = true
isOn = false isOn = false
isAnimated = true isAnimated = true
showText = false showText = false
@ -197,7 +200,7 @@ open class Toggle: Control, Changeable {
updateLabel() updateLabel()
toggleView.surface = surface toggleView.surface = surface
toggleView.disabled = disabled toggleView.isEnabled = isEnabled
toggleView.isOn = isOn toggleView.isOn = isOn
} }
@ -223,6 +226,7 @@ open class Toggle: Control, Changeable {
private var showLabel: Bool { private var showLabel: Bool {
showText && !statusText.isEmpty showText && !statusText.isEmpty
} }
private func updateLabel() { private func updateLabel() {
label.isHidden = !showLabel label.isHidden = !showLabel
@ -231,7 +235,7 @@ open class Toggle: Control, Changeable {
label.textStyle = textStyle label.textStyle = textStyle
label.text = statusText label.text = statusText
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
switch textPosition { switch textPosition {
case .left: case .left:
NSLayoutConstraint.deactivate(rightConstraints) NSLayoutConstraint.deactivate(rightConstraints)
@ -246,7 +250,6 @@ open class Toggle: Control, Changeable {
NSLayoutConstraint.deactivate(rightConstraints) NSLayoutConstraint.deactivate(rightConstraints)
NSLayoutConstraint.deactivate(labelConstraints) NSLayoutConstraint.deactivate(labelConstraints)
} }
invalidateIntrinsicContentSize()
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -117,19 +117,22 @@ open class ToggleView: Control, Changeable {
isAccessibilityElement = true isAccessibilityElement = true
accessibilityTraits = .button accessibilityTraits = .button
addSubview(toggleView) addSubview(toggleView)
toggleView.addSubview(knobView) toggleView.addSubview(knobView)
NSLayoutConstraint.activate([ toggleView.pinToSuperView()
toggleView.widthAnchor.constraint(equalToConstant: toggleSize.width),
toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height), toggleView
toggleView.centerYAnchor.constraint(equalTo: centerYAnchor), .width(toggleSize.width)
knobView.heightAnchor.constraint(equalToConstant: knobSize.height), .height(toggleSize.height)
knobView.widthAnchor.constraint(equalToConstant: knobSize.width),
knobView.centerYAnchor.constraint(equalTo: toggleView.centerYAnchor), knobView
knobView.topAnchor.constraint(greaterThanOrEqualTo: toggleView.topAnchor) .pinTopGreaterThanOrEqualTo()
]) .width(knobSize.width)
.height(knobSize.height)
knobView.centerYAnchor.constraint(equalTo: toggleView.centerYAnchor).activate()
// Set cornerRadius // Set cornerRadius
knobView.layer.cornerRadius = knobSize.height / 2.0 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 // Update shadow layers frames to match the view's bounds
knobView.layer.insertSublayer(shadowLayer1, at: 0) knobView.layer.insertSublayer(shadowLayer1, at: 0)
knobView.layer.insertSublayer(shadowLayer2, 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. /// Resets to default settings.
@ -225,7 +215,7 @@ open class ToggleView: Control, Changeable {
shadowLayer1.backgroundColor = knobColor.cgColor shadowLayer1.backgroundColor = knobColor.cgColor
shadowLayer2.backgroundColor = knobColor.cgColor shadowLayer2.backgroundColor = knobColor.cgColor
if disabled || !isAnimated { if !isEnabled || !isAnimated {
toggleView.backgroundColor = toggleColor toggleView.backgroundColor = toggleColor
knobView.backgroundColor = knobColor knobView.backgroundColor = knobColor
constrainKnob() constrainKnob()
@ -246,6 +236,19 @@ open class ToggleView: Control, Changeable {
shadowLayer1.frame = knobView.bounds shadowLayer1.frame = knobView.bounds
shadowLayer2.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
} }
} }

View File

@ -38,10 +38,10 @@ open class Tooltip: Control, TooltipLaunchable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
open var imageView = UIImageView().with { open var icon = Icon().with {
$0.translatesAutoresizingMaskIntoConstraints = false $0.name = .info
$0.contentMode = .scaleAspectFill $0.size = .small
$0.clipsToBounds = true $0.isUserInteractionEnabled = false
} }
open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }} open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }}
@ -111,18 +111,8 @@ open class Tooltip: Control, TooltipLaunchable {
open override func setup() { open override func setup() {
super.setup() super.setup()
if let image = BundleManager.shared.image(for: "info") { addSubview(icon)
infoImage = image icon.pinToSuperView()
}
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
backgroundColor = .clear backgroundColor = .clear
isAccessibilityElement = true isAccessibilityElement = true
@ -149,7 +139,6 @@ open class Tooltip: Control, TooltipLaunchable {
content = "" content = ""
fillColor = .primary fillColor = .primary
closeButtonText = "Close" closeButtonText = "Close"
imageView.image = nil
shouldUpdateView = true shouldUpdateView = true
setNeedsUpdate() 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. /// Function used to make changes to the View based off a change events or from local properties.
open override func updateView() { open override func updateView() {
super.updateView() super.updateView()
//set the dimensions //get the size
let dimensions = size.value.dimensions icon.size = size.value
heightConstraint?.constant = dimensions.height
widthConstraint?.constant = dimensions.width
//get the color for the image //get the color for the image
let imageColor = iconColorConfiguration.getColor(self) icon.color = iconColorConfiguration.getColor(self)
imageView.image = infoImage.withTintColor(imageColor)
} }
open override func updateAccessibility() { open override func updateAccessibility() {

View File

@ -71,8 +71,8 @@ open class TrailingTooltipLabel: View, TooltipLaunchable {
label.textPosition = labelTextPosition label.textPosition = labelTextPosition
label.attributes = labelAttributes label.attributes = labelAttributes
label.surface = surface label.surface = surface
label.disabled = disabled label.isEnabled = isEnabled
//add tooltip //add tooltip
if let labelText, !labelText.isEmpty { if let labelText, !labelText.isEmpty {
label.addTooltip(model: .init(surface: surface, closeButtonText: tooltipCloseButtonText, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView)) label.addTooltip(model: .init(surface: surface, closeButtonText: tooltipCloseButtonText, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView))

View File

@ -10,466 +10,11 @@ import UIKit
import VDSFormControlsTokens import VDSFormControlsTokens
extension UIView { extension UIView {
public func constraint(with identifier: String) -> NSLayoutConstraint? { public func constraint(with identifier: String) -> NSLayoutConstraint? {
return constraints.first { $0.identifier == identifier } 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 { extension NSLayoutConstraint {
@discardableResult @discardableResult

View File

@ -7,8 +7,8 @@
import Foundation import Foundation
/// Any object that can be disabled, which may change the appearance ///// Any object that can be disabled, which may change the appearance
public protocol Disabling { //public protocol Disabling {
/// Whether this object is disabled or not // /// Whether this object is disabled or not
var disabled: Bool { get set } // var disabled: Bool { get set }
} //}

View File

@ -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 }
}

View File

@ -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
}
}

View File

@ -9,7 +9,7 @@ import Foundation
import UIKit import UIKit
import Combine 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. /// Set of Subscribers for any Publishers for this Control.
var subscribers: Set<AnyCancellable> { get set } var subscribers: Set<AnyCancellable> { get set }

View File

@ -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 1.0.39
======= =======
- CXTDT-423141 - Tabs - Selected Tab dark mode text color - CXTDT-423141 - Tabs - Selected Tab dark mode text color