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