Merge branch 'feature/badgeIndicator' into 'develop'
updated images for vector See merge request BPHV_MIPS/vds_ios!80
This commit is contained in:
commit
bc65e0e186
@ -106,6 +106,10 @@
|
|||||||
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
|
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
|
||||||
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; };
|
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; };
|
||||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; };
|
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; };
|
||||||
|
EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A62A3B67770015965D /* UIView+CALayer.swift */; };
|
||||||
|
EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */; };
|
||||||
|
EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */; };
|
||||||
|
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */; };
|
||||||
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; };
|
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; };
|
||||||
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; };
|
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; };
|
||||||
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; };
|
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; };
|
||||||
@ -237,6 +241,10 @@
|
|||||||
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
||||||
EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = "<group>"; };
|
EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = "<group>"; };
|
||||||
EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
||||||
|
EAD062A62A3B67770015965D /* UIView+CALayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+CALayer.swift"; sourceTree = "<group>"; };
|
||||||
|
EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutAnchor.swift; sourceTree = "<group>"; };
|
||||||
|
EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutDimension.swift; sourceTree = "<group>"; };
|
||||||
|
EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicator.swift; sourceTree = "<group>"; };
|
||||||
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
|
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
|
||||||
EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = "<group>"; };
|
EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = "<group>"; };
|
||||||
EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = "<group>"; };
|
EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = "<group>"; };
|
||||||
@ -394,6 +402,7 @@
|
|||||||
EA33619D288B1E330071C351 /* Components */ = {
|
EA33619D288B1E330071C351 /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
EAD062AE2A3B87210015965D /* BadgeIndicator */,
|
||||||
EA4DB2FE28DCBC1900103EE3 /* Badge */,
|
EA4DB2FE28DCBC1900103EE3 /* Badge */,
|
||||||
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
||||||
EAF7F092289985E200B287F5 /* Checkbox */,
|
EAF7F092289985E200B287F5 /* Checkbox */,
|
||||||
@ -429,12 +438,15 @@
|
|||||||
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
|
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
|
||||||
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
|
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
|
||||||
EABFEB632A26473700C4C106 /* NSAttributedString.swift */,
|
EABFEB632A26473700C4C106 /* NSAttributedString.swift */,
|
||||||
|
EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */,
|
||||||
|
EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */,
|
||||||
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
|
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
|
||||||
EA3361A7288B23300071C351 /* UIColor.swift */,
|
EA3361A7288B23300071C351 /* UIColor.swift */,
|
||||||
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
|
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
|
||||||
EA33623D2892EE950071C351 /* UIDevice.swift */,
|
EA33623D2892EE950071C351 /* UIDevice.swift */,
|
||||||
EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */,
|
EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */,
|
||||||
EAB5FED329267EB300998C17 /* UIView.swift */,
|
EAB5FED329267EB300998C17 /* UIView.swift */,
|
||||||
|
EAD062A62A3B67770015965D /* UIView+CALayer.swift */,
|
||||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
|
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
|
||||||
EA985C662970C21600F2FF2E /* VDSLayout.swift */,
|
EA985C662970C21600F2FF2E /* VDSLayout.swift */,
|
||||||
);
|
);
|
||||||
@ -686,6 +698,14 @@
|
|||||||
path = EntryField;
|
path = EntryField;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
EAD062AE2A3B87210015965D /* BadgeIndicator */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */,
|
||||||
|
);
|
||||||
|
path = BadgeIndicator;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
EAF7F092289985E200B287F5 /* Checkbox */ = {
|
EAF7F092289985E200B287F5 /* Checkbox */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -884,6 +904,7 @@
|
|||||||
EA33624728931B050071C351 /* Initable.swift in Sources */,
|
EA33624728931B050071C351 /* Initable.swift in Sources */,
|
||||||
EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */,
|
EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */,
|
||||||
EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */,
|
EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */,
|
||||||
|
EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */,
|
||||||
EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */,
|
EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */,
|
||||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */,
|
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */,
|
||||||
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */,
|
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */,
|
||||||
@ -917,6 +938,7 @@
|
|||||||
EA336171288B19200071C351 /* VDS.docc in Sources */,
|
EA336171288B19200071C351 /* VDS.docc in Sources */,
|
||||||
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
||||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
||||||
|
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
||||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
||||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
||||||
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
|
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
|
||||||
@ -927,6 +949,7 @@
|
|||||||
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
|
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
|
||||||
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
|
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
|
||||||
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
||||||
|
EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */,
|
||||||
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
||||||
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
||||||
EA985C672970C21600F2FF2E /* VDSLayout.swift in Sources */,
|
EA985C672970C21600F2FF2E /* VDSLayout.swift in Sources */,
|
||||||
@ -941,6 +964,7 @@
|
|||||||
EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */,
|
EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */,
|
||||||
EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */,
|
EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */,
|
||||||
EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */,
|
EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */,
|
||||||
|
EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */,
|
||||||
EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */,
|
EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */,
|
||||||
5FC35BE328D51405004EBEAC /* Button.swift in Sources */,
|
5FC35BE328D51405004EBEAC /* Button.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
329
VDS/Components/BadgeIndicator/BadgeIndicator.swift
Normal file
329
VDS/Components/BadgeIndicator/BadgeIndicator.swift
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
//
|
||||||
|
// Badge.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 9/22/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import VDSColorTokens
|
||||||
|
import VDSFormControlsTokens
|
||||||
|
import Combine
|
||||||
|
import VDSTypographyTokens
|
||||||
|
|
||||||
|
/// Badges are visual labels used to convey status or highlight supplemental information.
|
||||||
|
@objc(VDSBadgeIndicator)
|
||||||
|
open class BadgeIndicator: View {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Enums
|
||||||
|
//--------------------------------------------------
|
||||||
|
public enum FillColor: String, CaseIterable {
|
||||||
|
case red, yellow, green, orange, blue, gray, grayLowContrast, black, white
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Kind: String, CaseIterable {
|
||||||
|
case simple, numbered
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MaxDigits: String, CaseIterable {
|
||||||
|
case one
|
||||||
|
case two
|
||||||
|
case three
|
||||||
|
case four
|
||||||
|
case five
|
||||||
|
case six
|
||||||
|
|
||||||
|
public var value: Int {
|
||||||
|
switch self {
|
||||||
|
case .two:
|
||||||
|
return 2
|
||||||
|
case .one:
|
||||||
|
return 1
|
||||||
|
case .three:
|
||||||
|
return 3
|
||||||
|
case .four:
|
||||||
|
return 4
|
||||||
|
case .five:
|
||||||
|
return 5
|
||||||
|
case .six:
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TextSize: String, CaseIterable {
|
||||||
|
case xxlarge = "2XLarge"
|
||||||
|
case xlarge = "XLarge"
|
||||||
|
case large = "Large"
|
||||||
|
case medium = "Medium"
|
||||||
|
case small = "Small"
|
||||||
|
|
||||||
|
public var minimumSize: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .xxlarge:
|
||||||
|
return 29
|
||||||
|
case .xlarge:
|
||||||
|
return 24
|
||||||
|
case .large:
|
||||||
|
return 20
|
||||||
|
case .medium:
|
||||||
|
return 18
|
||||||
|
case .small:
|
||||||
|
return 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var padding: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .xxlarge:
|
||||||
|
return 8
|
||||||
|
case .xlarge:
|
||||||
|
return 6
|
||||||
|
case .large:
|
||||||
|
return 6
|
||||||
|
case .medium:
|
||||||
|
return 6
|
||||||
|
case .small:
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var textStyle: TextStyle {
|
||||||
|
let style = TextStyle.bodySmall
|
||||||
|
var pointSize: CGFloat = VDSTypography.fontSizeBody12
|
||||||
|
|
||||||
|
switch self {
|
||||||
|
case .xxlarge:
|
||||||
|
pointSize = VDSTypography.fontSizeTitle24
|
||||||
|
|
||||||
|
case .xlarge:
|
||||||
|
pointSize = VDSTypography.fontSizeTitle20
|
||||||
|
|
||||||
|
case .large:
|
||||||
|
pointSize = VDSTypography.fontSizeBody16
|
||||||
|
|
||||||
|
case .medium:
|
||||||
|
pointSize = VDSTypography.fontSizeBody14
|
||||||
|
|
||||||
|
case .small:
|
||||||
|
pointSize = VDSTypography.fontSizeBody12
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextStyle(rawValue: "\(self.rawValue)BadgeIndicator",
|
||||||
|
fontFace: style.fontFace,
|
||||||
|
pointSize: pointSize,
|
||||||
|
lineHeight: style.lineHeight,
|
||||||
|
letterSpacing: style.letterSpacing)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Public Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
open var label = Label().with {
|
||||||
|
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
$0.adjustsFontSizeToFitWidth = false
|
||||||
|
$0.lineBreakMode = .byTruncatingTail
|
||||||
|
$0.textPosition = .center
|
||||||
|
$0.numberOfLines = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
open var borderColorLight: UIColor? {
|
||||||
|
didSet {
|
||||||
|
if let borderColorLight {
|
||||||
|
borderColorConfiguration.lightColor = borderColorLight
|
||||||
|
} else {
|
||||||
|
borderColorConfiguration.lightColor = VDSColor.paletteWhite
|
||||||
|
}
|
||||||
|
setNeedsUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open var borderColorDark: UIColor? {
|
||||||
|
didSet {
|
||||||
|
if let borderColorDark {
|
||||||
|
borderColorConfiguration.darkColor = borderColorDark
|
||||||
|
} else {
|
||||||
|
borderColorConfiguration.darkColor = VDSColor.paletteBlack
|
||||||
|
}
|
||||||
|
setNeedsUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var number: Int? { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var kind: Kind = .simple { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var leadingCharacter: String? { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var textSize: TextSize = .xxlarge { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var hideDot: Bool = false { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var hideBorder: Bool = false { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
open var maxDigits: MaxDigits = .two { didSet { setNeedsUpdate() }}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
private var labelWidthConstraint: NSLayoutConstraint?
|
||||||
|
private var labelHeightConstraint: NSLayoutConstraint?
|
||||||
|
private var defaultBadgeSize: CGFloat = 16
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setup() {
|
||||||
|
super.setup()
|
||||||
|
|
||||||
|
accessibilityElements = [label]
|
||||||
|
|
||||||
|
addSubview(label)
|
||||||
|
label.pinToSuperView()
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
label.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||||
|
label.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
labelWidthConstraint = label.widthGreaterThanEqualTo(constant: defaultBadgeSize).activate()
|
||||||
|
labelHeightConstraint = label.heightGreaterThanEqualTo(constant: defaultBadgeSize).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
super.reset()
|
||||||
|
shouldUpdateView = false
|
||||||
|
label.reset()
|
||||||
|
label.lineBreakMode = .byTruncatingTail
|
||||||
|
label.textPosition = .center
|
||||||
|
fillColor = .red
|
||||||
|
number = nil
|
||||||
|
shouldUpdateView = true
|
||||||
|
setNeedsUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Configuration
|
||||||
|
//--------------------------------------------------
|
||||||
|
private var borderColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteBlack)
|
||||||
|
|
||||||
|
private var backgroundColorConfiguration: AnyColorable = {
|
||||||
|
let config = KeyedColorConfiguration<BadgeIndicator, FillColor>(keyPath: \.fillColor)
|
||||||
|
config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteYellow53, VDSColor.paletteYellow53, forKey: .yellow)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forKey: .green)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteOrange41, VDSColor.paletteOrange58, forKey: .orange)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteBlue38, VDSColor.paletteBlue46, forKey: .blue)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteGray44, VDSColor.paletteGray65, forKey: .gray)
|
||||||
|
config.setSurfaceColors(VDSColor.paletteGray85, VDSColor.paletteGray20, forKey: .grayLowContrast)
|
||||||
|
config.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryDark, forKey: .black)
|
||||||
|
config.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forKey: .white)
|
||||||
|
return config.eraseToAnyColorable()
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var textColorConfiguration = ViewColorConfiguration()
|
||||||
|
|
||||||
|
public func updateTextColorConfig() {
|
||||||
|
textColorConfiguration.reset()
|
||||||
|
|
||||||
|
switch fillColor {
|
||||||
|
|
||||||
|
case .red, .black, .gray, .grayLowContrast:
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
||||||
|
|
||||||
|
case .yellow, .white:
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||||
|
|
||||||
|
case .orange, .green, .blue:
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||||
|
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - State
|
||||||
|
//--------------------------------------------------
|
||||||
|
open override func updateView() {
|
||||||
|
updateTextColorConfig()
|
||||||
|
|
||||||
|
backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||||
|
|
||||||
|
label.useAttributedText = true
|
||||||
|
label.edgeInset = .init(top: 0, left: textSize.padding, bottom: 0, right: textSize.padding)
|
||||||
|
label.font = textSize.textStyle.font
|
||||||
|
label.textColor = textColorConfiguration.getColor(self)
|
||||||
|
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
|
||||||
|
label.text = getText()
|
||||||
|
label.surface = surface
|
||||||
|
label.disabled = disabled
|
||||||
|
label.sizeToFit()
|
||||||
|
setNeedsLayout()
|
||||||
|
layoutIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getText() -> String {
|
||||||
|
let badgeCount = number ?? 0
|
||||||
|
var text: String = ""
|
||||||
|
if kind == .numbered && badgeCount >= 0 {
|
||||||
|
let maxBadgetCount = limitDigits(number: badgeCount, maxDigits: maxDigits.value)
|
||||||
|
let formatter = NumberFormatter()
|
||||||
|
formatter.numberStyle = .decimal
|
||||||
|
text = formatter.string(from: .init(integerLiteral: maxBadgetCount))!
|
||||||
|
if maxDigits.value < "\(badgeCount)".count {
|
||||||
|
let formatter = NumberFormatter()
|
||||||
|
formatter.numberStyle = .decimal
|
||||||
|
text = "\(text)+"
|
||||||
|
}
|
||||||
|
if let leadingCharacter {
|
||||||
|
text = "\(leadingCharacter)\(text)"
|
||||||
|
} else {
|
||||||
|
text = "\(text)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
private func limitDigits(number: Int, maxDigits: Int) -> Int {
|
||||||
|
let maxNumber = Int(pow(10.0, Double(maxDigits))) - 1
|
||||||
|
return min(number, maxNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
labelWidthConstraint?.constant = textSize.minimumSize
|
||||||
|
labelHeightConstraint?.constant = textSize.minimumSize
|
||||||
|
layer.cornerRadius = frame.size.height / 2
|
||||||
|
|
||||||
|
if hideBorder {
|
||||||
|
layer.borderWidth = 0
|
||||||
|
} else {
|
||||||
|
layer.borderColor = borderColorConfiguration.getColor(surface).cgColor
|
||||||
|
layer.borderWidth = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.remove(layerName: "dot")
|
||||||
|
if kind == .simple && !hideDot {
|
||||||
|
let dotSize: CGFloat = bounds.width * 0.1875
|
||||||
|
let dotLayer = CAShapeLayer()
|
||||||
|
dotLayer.name = "dot"
|
||||||
|
|
||||||
|
let centerX = (bounds.width - dotSize) / 2.0
|
||||||
|
let centerY = (bounds.width - dotSize) / 2.0
|
||||||
|
|
||||||
|
dotLayer.frame = .init(x: centerX, y: centerY, width: dotSize, height: dotSize)
|
||||||
|
dotLayer.path = UIBezierPath(ovalIn: .init(origin: .zero, size: .init(width: dotSize, height: dotSize))).cgPath
|
||||||
|
dotLayer.fillColor = textColorConfiguration.getColor(self).cgColor
|
||||||
|
|
||||||
|
layer.addSublayer(dotLayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -172,13 +172,13 @@ open class ButtonIcon: Control {
|
|||||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
var shadowColorConfiguration: AnyColorable = {
|
var shadowColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.paletteBlack, .clear).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
var shadowOpacity: CGFloat = 0.5
|
var shadowOpacity: CGFloat = 0.16
|
||||||
var shadowOffset: CGSize = .init(width: 1, height: 1)
|
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
||||||
var shadowRadius: CGFloat = 2
|
var shadowRadius: CGFloat = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct HighContrastConfiguration: Configuration {
|
private struct HighContrastConfiguration: Configuration {
|
||||||
var kind: Kind = .highContrast
|
var kind: Kind = .highContrast
|
||||||
var surfaceType: SurfaceType = .colorFill
|
var surfaceType: SurfaceType = .colorFill
|
||||||
@ -280,7 +280,6 @@ open class ButtonIcon: Control {
|
|||||||
} else {
|
} else {
|
||||||
icon.reset()
|
icon.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
setNeedsLayout()
|
setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,26 +315,15 @@ open class ButtonIcon: Control {
|
|||||||
if let borderable = currentConfig as? Borderable {
|
if let borderable = currentConfig as? Borderable {
|
||||||
layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor
|
layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor
|
||||||
layer.borderWidth = borderable.borderWidth
|
layer.borderWidth = borderable.borderWidth
|
||||||
icon.layer.borderWidth = borderable.borderWidth
|
|
||||||
} else {
|
} else {
|
||||||
layer.borderColor = nil
|
layer.borderColor = nil
|
||||||
layer.borderWidth = 0
|
layer.borderWidth = 0
|
||||||
icon.layer.borderWidth = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let dropshadowable = currentConfig as? Dropshadowable {
|
if let dropshadowable = currentConfig as? Dropshadowable {
|
||||||
layer.masksToBounds = false
|
addDropShadow(config: dropshadowable)
|
||||||
layer.shadowColor = dropshadowable.shadowColorConfiguration.getColor(self).cgColor
|
|
||||||
layer.shadowOpacity = Float(dropshadowable.shadowOpacity)
|
|
||||||
layer.shadowOffset = dropshadowable.shadowOffset
|
|
||||||
layer.shadowRadius = dropshadowable.shadowRadius
|
|
||||||
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
|
|
||||||
layer.shouldRasterize = true
|
|
||||||
layer.rasterizationScale = UIScreen.main.scale
|
|
||||||
} else {
|
} else {
|
||||||
layer.shadowOpacity = 0
|
removeDropShadow()
|
||||||
layer.shadowRadius = 0
|
|
||||||
layer.shadowPath = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -360,6 +348,25 @@ extension ButtonIcon: AppleGuidlinesTouchable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension UIView {
|
||||||
|
fileprivate func addDropShadow(config: Dropshadowable) {
|
||||||
|
layer.masksToBounds = false
|
||||||
|
layer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor
|
||||||
|
layer.shadowOpacity = Float(config.shadowOpacity)
|
||||||
|
layer.shadowOffset = config.shadowOffset
|
||||||
|
layer.shadowRadius = config.shadowRadius
|
||||||
|
layer.shouldRasterize = true
|
||||||
|
layer.rasterizationScale = UIScreen.main.scale
|
||||||
|
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius).cgPath
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func removeDropShadow() {
|
||||||
|
layer.shadowOpacity = 0
|
||||||
|
layer.shadowRadius = 0
|
||||||
|
layer.shadowPath = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private protocol Borderable {
|
private protocol Borderable {
|
||||||
var borderWidth: CGFloat { get set }
|
var borderWidth: CGFloat { get set }
|
||||||
var borderColorConfiguration: AnyColorable { get set }
|
var borderColorConfiguration: AnyColorable { get set }
|
||||||
|
|||||||
@ -39,6 +39,14 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
|||||||
|
|
||||||
open var userInfo = [String: Primitive]()
|
open var userInfo = [String: Primitive]()
|
||||||
|
|
||||||
|
open var edgeInset: UIEdgeInsets = .zero {
|
||||||
|
didSet {
|
||||||
|
setNeedsUpdate()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override open var text: String? {
|
override open var text: String? {
|
||||||
didSet {
|
didSet {
|
||||||
attributes = nil
|
attributes = nil
|
||||||
@ -192,7 +200,16 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
|||||||
attributedString.addAttribute( .paragraphStyle, value: paragraph, range: entireRange)
|
attributedString.addAttribute( .paragraphStyle, value: paragraph, range: entireRange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open override func drawText(in rect: CGRect) {
|
||||||
|
super.drawText(in: rect.inset(by: edgeInset))
|
||||||
|
}
|
||||||
|
|
||||||
|
open override var intrinsicContentSize: CGSize {
|
||||||
|
let size = super.intrinsicContentSize
|
||||||
|
return CGSize(width: size.width + edgeInset.left + edgeInset.right, height: size.height + edgeInset.top + edgeInset.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Actionable
|
// MARK: - Actionable
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -11,7 +11,7 @@ extension TitleLockup {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Enums
|
// MARK: - Enums
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public enum TitleTextStyle: String, EnumSubset {
|
public enum TitleTextStyle: String, CaseIterable {
|
||||||
|
|
||||||
case featureMedium
|
case featureMedium
|
||||||
case boldFeatureMedium
|
case boldFeatureMedium
|
||||||
@ -32,9 +32,14 @@ extension TitleLockup {
|
|||||||
case boldTitleSmall
|
case boldTitleSmall
|
||||||
|
|
||||||
public var defaultValue: TextStyle {.boldFeatureXSmall }
|
public var defaultValue: TextStyle {.boldFeatureXSmall }
|
||||||
|
|
||||||
|
public var value: TextStyle {
|
||||||
|
TextStyle.textStyle(for: self.rawValue) ?? defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OtherTextStyle: String, EnumSubset {
|
public enum OtherTextStyle: String, CaseIterable {
|
||||||
case bodyLarge
|
case bodyLarge
|
||||||
case boldBodyLarge
|
case boldBodyLarge
|
||||||
case bodyMedium
|
case bodyMedium
|
||||||
@ -43,6 +48,9 @@ extension TitleLockup {
|
|||||||
case boldBodySmall
|
case boldBodySmall
|
||||||
|
|
||||||
public var defaultValue: TextStyle {.bodyLarge }
|
public var defaultValue: TextStyle {.bodyLarge }
|
||||||
|
|
||||||
|
public var value: TextStyle {
|
||||||
|
TextStyle.textStyle(for: self.rawValue) ?? defaultValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
58
VDS/Extensions/NSLayoutAnchor.swift
Normal file
58
VDS/Extensions/NSLayoutAnchor.swift
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// NSLayoutAnchor.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 6/15/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - NSLayoutAnchor
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension NSLayoutAnchor {
|
||||||
|
// These methods return an inactive constraint of the form thisAnchor = otherAnchor.
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(equalTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(equalTo: anchor)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(greaterThanOrEqualTo: anchor)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(lessThanOrEqualTo: anchor)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(equalTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(equalTo: anchor, constant: constant)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(greaterThanOrEqualTo: anchor, constant: constant)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let constraint = self.constraint(lessThanOrEqualTo: anchor, constant: constant)
|
||||||
|
constraint.identifier = identifier
|
||||||
|
return constraint
|
||||||
|
}
|
||||||
|
}
|
||||||
84
VDS/Extensions/NSLayoutDimension.swift
Normal file
84
VDS/Extensions/NSLayoutDimension.swift
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// NSLayoutDimension.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 6/15/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - NSLayoutDimension
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension NSLayoutDimension {
|
||||||
|
// These methods return an inactive constraint of the form thisVariable = constant.
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(equalToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(equalToConstant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(greaterThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(greaterThanOrEqualToConstant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(lessThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(lessThanOrEqualToConstant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier.
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(equalTo: anchor, multiplier: m)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(greaterThanOrEqualTo: anchor ,multiplier: m)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier + constant.
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(equalTo: anchor, multiplier: m, constant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(greaterThanOrEqualTo: anchor, multiplier: m, constant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
@objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint {
|
||||||
|
let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m, constant: c)
|
||||||
|
lc.identifier = identifier
|
||||||
|
return lc
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -119,4 +119,11 @@ extension UIColor {
|
|||||||
guard let _ = found else { return false}
|
guard let _ = found else { return false}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func toVDSColor() -> VDSColor? {
|
||||||
|
guard let hex = hexString else { return nil }
|
||||||
|
let found = VDSColor.allCases.first{ $0.uiColor.hexString == hex }
|
||||||
|
guard let found else { return nil}
|
||||||
|
return found
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
140
VDS/Extensions/UIView+CALayer.swift
Normal file
140
VDS/Extensions/UIView+CALayer.swift
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
//
|
||||||
|
// UIView+CALayer.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 6/15/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import VDSFormControlsTokens
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Debug Borders
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
|
internal func removeDebugBorder() {
|
||||||
|
layer.remove(layerName: "debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func addDebugBorder(color: UIColor = .red) {
|
||||||
|
//ensure you remove existing
|
||||||
|
removeDebugBorder()
|
||||||
|
|
||||||
|
//add bounds border
|
||||||
|
let borderLayer = CALayer()
|
||||||
|
borderLayer.name = "debugAreaLayer"
|
||||||
|
borderLayer.frame = bounds
|
||||||
|
borderLayer.bounds = bounds
|
||||||
|
borderLayer.borderWidth = VDSFormControls.widthBorder
|
||||||
|
borderLayer.borderColor = color.cgColor
|
||||||
|
layer.addSublayer(borderLayer)
|
||||||
|
|
||||||
|
//add touchborder if applicable
|
||||||
|
if type(of: self) is AppleGuidlinesTouchable.Type {
|
||||||
|
let faultToleranceX: CGFloat = max((45 - bounds.size.width) / 2.0, 0)
|
||||||
|
let faultToleranceY: CGFloat = max((45 - bounds.size.height) / 2.0, 0)
|
||||||
|
|
||||||
|
let touchableAreaPath = UIBezierPath(rect: bounds.insetBy(dx: -faultToleranceX, dy: -faultToleranceY))
|
||||||
|
let touchLayer = CAShapeLayer()
|
||||||
|
touchLayer.path = touchableAreaPath.cgPath
|
||||||
|
touchLayer.strokeColor = color.cgColor
|
||||||
|
touchLayer.fillColor = UIColor.clear.cgColor
|
||||||
|
touchLayer.lineWidth = VDSFormControls.widthBorder
|
||||||
|
touchLayer.opacity = 1.0
|
||||||
|
touchLayer.name = "debugTouchableAreaLayer"
|
||||||
|
touchLayer.zPosition = 100
|
||||||
|
touchLayer.frame = bounds
|
||||||
|
touchLayer.bounds = bounds
|
||||||
|
layer.addSublayer(touchLayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var hasDebugBorder: Bool {
|
||||||
|
guard let layers = layer.sublayers else { return false }
|
||||||
|
return layers.compactMap{$0.name}.filter{$0.hasPrefix("debug")}.count > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public func debugBorder(show shouldShow: Bool = true, color: UIColor = .red) {
|
||||||
|
if shouldShow {
|
||||||
|
addDebugBorder(color: color)
|
||||||
|
} else {
|
||||||
|
removeDebugBorder()
|
||||||
|
}
|
||||||
|
if let view = self as? Handlerable {
|
||||||
|
view.updateView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - CALayer
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension CALayer {
|
||||||
|
func remove(layerName: String) {
|
||||||
|
guard let sublayers = sublayers else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sublayers.forEach({ layer in
|
||||||
|
if layer.name?.hasPrefix(layerName) ?? false {
|
||||||
|
layer.removeFromSuperlayer()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Borders
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
|
public func addBorder(side: UIRectEdge, width: CGFloat, color: UIColor, offset: CGFloat = 0) {
|
||||||
|
let layerName = borderLayerName(for: side)
|
||||||
|
layer.remove(layerName: layerName)
|
||||||
|
|
||||||
|
let borderLayer = CALayer()
|
||||||
|
borderLayer.backgroundColor = color.cgColor
|
||||||
|
borderLayer.name = layerName
|
||||||
|
|
||||||
|
switch side {
|
||||||
|
case .left:
|
||||||
|
borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: frame.height)
|
||||||
|
case .right:
|
||||||
|
borderLayer.frame = CGRect(x: frame.width - width - offset, y: 0, width: width, height: frame.height)
|
||||||
|
case .top:
|
||||||
|
borderLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: width)
|
||||||
|
case .bottom:
|
||||||
|
borderLayer.frame = CGRect(x: 0, y: frame.height - width - offset, width: frame.width, height: width)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.addSublayer(borderLayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func removeBorders() {
|
||||||
|
layer.borderWidth = 0
|
||||||
|
layer.borderColor = nil
|
||||||
|
layer.remove(layerName: borderLayerName(for: .top))
|
||||||
|
layer.remove(layerName: borderLayerName(for: .left))
|
||||||
|
layer.remove(layerName: borderLayerName(for: .right))
|
||||||
|
layer.remove(layerName: borderLayerName(for: .bottom))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func borderLayerName(for side: UIRectEdge) -> String {
|
||||||
|
switch side {
|
||||||
|
case .left:
|
||||||
|
return "leftBorderLayer"
|
||||||
|
case .right:
|
||||||
|
return "rightBorderLayer"
|
||||||
|
case .top:
|
||||||
|
return "topBorderLayer"
|
||||||
|
case .bottom:
|
||||||
|
return "bottomBorderLayer"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,56 +10,118 @@ import UIKit
|
|||||||
import VDSFormControlsTokens
|
import VDSFormControlsTokens
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) {
|
|
||||||
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edges.left).isActive = true
|
public func constraint(with identifier: String) -> NSLayoutConstraint? {
|
||||||
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -edges.right).isActive = true
|
return constraints.first { $0.identifier == identifier }
|
||||||
topAnchor.constraint(equalTo: view.topAnchor, constant: edges.top).isActive = true
|
|
||||||
bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -edges.bottom).isActive = true
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) {
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Pinning
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
@discardableResult
|
||||||
|
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
|
||||||
|
public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self {
|
||||||
if let superview {
|
if let superview {
|
||||||
pin(superview, with: edges)
|
pin(superview, with: edges)
|
||||||
}
|
}
|
||||||
|
return self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - HeightAnchor
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func height(_ constant: CGFloat) -> Self {
|
public func height(_ constant: CGFloat) -> Self {
|
||||||
heightAnchor.constraint(equalToConstant: constant).isActive = true
|
height(constant: constant)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func heightGreaterThanEqual(_ constant: CGFloat) -> Self {
|
public func heightGreaterThanEqualTo(_ constant: CGFloat) -> Self {
|
||||||
heightAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true
|
heightGreaterThanEqualTo(constant: constant)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
public func heightLessThanEqual(_ constant: CGFloat) -> Self {
|
|
||||||
heightAnchor.constraint(lessThanOrEqualToConstant: constant).isActive = true
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
public func width(_ constant: CGFloat) -> Self {
|
|
||||||
widthAnchor.constraint(equalToConstant: constant).isActive = true
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func widthGreaterThanEqual(_ constant: CGFloat) -> Self {
|
public func heightLessThanEqualTo(_ constant: CGFloat) -> Self {
|
||||||
widthAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true
|
heightLessThanEqualTo(constant: constant)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func height(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
|
heightAnchor.constraint(equalToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func widthLessThanEqual(_ constant: CGFloat) -> Self {
|
public func heightGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
widthAnchor.constraint(lessThanOrEqualToConstant: constant).isActive = true
|
heightAnchor.constraint(greaterThanOrEqualToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func heightLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
|
heightAnchor.constraint(lessThanOrEqualToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - WidthAnchor
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func width(_ constant: CGFloat) -> Self {
|
||||||
|
width(constant: constant)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func widthGreaterThanEqualTo(_ constant: CGFloat) -> Self {
|
||||||
|
widthGreaterThanEqualTo(constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func widthLessThanEqualTo(_ constant: CGFloat) -> Self {
|
||||||
|
widthLessThanEqualTo(constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func width(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
|
widthAnchor.constraint(equalToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func widthGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
|
widthAnchor.constraint(greaterThanOrEqualToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func widthLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint {
|
||||||
|
widthAnchor.constraint(lessThanOrEqualToConstant: constant).activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - TopAnchor
|
||||||
|
//--------------------------------------------------
|
||||||
|
extension UIView {
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func pinTop(_ constant: CGFloat = 0.0) -> Self {
|
public func pinTop(_ constant: CGFloat = 0.0) -> Self {
|
||||||
return pinTop(nil, constant)
|
return pinTop(nil, constant)
|
||||||
@ -67,13 +129,49 @@ extension UIView {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor
|
pinTop(anchor: anchor, constant: constant)
|
||||||
if let found {
|
|
||||||
topAnchor.constraint(equalTo: found, constant: constant).isActive = true
|
|
||||||
}
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinTopGreaterThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
@discardableResult
|
||||||
public func pinBottom(_ constant: CGFloat = 0.0) -> Self {
|
public func pinBottom(_ constant: CGFloat = 0.0) -> Self {
|
||||||
return pinBottom(nil, constant)
|
return pinBottom(nil, constant)
|
||||||
@ -81,161 +179,167 @@ extension UIView {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor
|
pinBottom(anchor: anchor, constant: constant)
|
||||||
if let found {
|
|
||||||
bottomAnchor.constraint(equalTo: found, constant: -constant).isActive = true
|
|
||||||
}
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinBottomGreaterThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
@discardableResult
|
||||||
public func pinLeading(_ constant: CGFloat = 0.0) -> Self {
|
public func pinLeading(_ constant: CGFloat = 0.0) -> Self {
|
||||||
return pinLeading(nil, constant)
|
return pinLeading(nil, constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor
|
pinLeading(anchor: anchor, constant: constant)
|
||||||
if let found {
|
|
||||||
leadingAnchor.constraint(equalTo: found, constant: constant).isActive = true
|
|
||||||
}
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinLeadingLessThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinLeadingGreaterThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
@discardableResult
|
||||||
public func pinTrailing(_ constant: CGFloat = 0.0) -> Self {
|
public func pinTrailing(_ constant: CGFloat = 0.0) -> Self {
|
||||||
return pinTrailing(nil, constant)
|
pinTrailing(nil, constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
|
pinTrailing(anchor: anchor, constant: constant)
|
||||||
if let found {
|
return self
|
||||||
trailingAnchor.constraint(equalTo: found, constant: -constant).isActive = true
|
}
|
||||||
}
|
|
||||||
|
@discardableResult
|
||||||
|
public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@discardableResult
|
||||||
|
public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||||
|
pinTrailingGreaterThanOrEqualTo(anchor: anchor, constant: constant)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
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
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
extension UIView {
|
@discardableResult
|
||||||
|
public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? {
|
||||||
internal func removeDebugBorder() {
|
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
|
||||||
layer.remove(layerName: "debug")
|
guard let found else { return nil }
|
||||||
}
|
return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate()
|
||||||
|
|
||||||
internal func addDebugBorder(color: UIColor = .red) {
|
|
||||||
//ensure you remove existing
|
|
||||||
removeDebugBorder()
|
|
||||||
|
|
||||||
//add bounds border
|
|
||||||
let borderLayer = CALayer()
|
|
||||||
borderLayer.name = "debugAreaLayer"
|
|
||||||
borderLayer.frame = bounds
|
|
||||||
borderLayer.bounds = bounds
|
|
||||||
borderLayer.borderWidth = VDSFormControls.widthBorder
|
|
||||||
borderLayer.borderColor = color.cgColor
|
|
||||||
layer.addSublayer(borderLayer)
|
|
||||||
|
|
||||||
//add touchborder if applicable
|
|
||||||
if type(of: self) is AppleGuidlinesTouchable.Type {
|
|
||||||
let faultToleranceX: CGFloat = max((45 - bounds.size.width) / 2.0, 0)
|
|
||||||
let faultToleranceY: CGFloat = max((45 - bounds.size.height) / 2.0, 0)
|
|
||||||
|
|
||||||
let touchableAreaPath = UIBezierPath(rect: bounds.insetBy(dx: -faultToleranceX, dy: -faultToleranceY))
|
|
||||||
let touchLayer = CAShapeLayer()
|
|
||||||
touchLayer.path = touchableAreaPath.cgPath
|
|
||||||
touchLayer.strokeColor = color.cgColor
|
|
||||||
touchLayer.fillColor = UIColor.clear.cgColor
|
|
||||||
touchLayer.lineWidth = VDSFormControls.widthBorder
|
|
||||||
touchLayer.opacity = 1.0
|
|
||||||
touchLayer.name = "debugTouchableAreaLayer"
|
|
||||||
touchLayer.zPosition = 100
|
|
||||||
touchLayer.frame = bounds
|
|
||||||
touchLayer.bounds = bounds
|
|
||||||
layer.addSublayer(touchLayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var hasDebugBorder: Bool {
|
|
||||||
guard let layers = layer.sublayers else { return false }
|
|
||||||
return layers.compactMap{$0.name}.filter{$0.hasPrefix("debug")}.count > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
public func debugBorder(show shouldShow: Bool = true, color: UIColor = .red) {
|
|
||||||
if shouldShow {
|
|
||||||
addDebugBorder(color: color)
|
|
||||||
} else {
|
|
||||||
removeDebugBorder()
|
|
||||||
}
|
|
||||||
if let view = self as? Handlerable {
|
|
||||||
view.updateView()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CALayer {
|
extension NSLayoutConstraint {
|
||||||
func remove(layerName: String) {
|
|
||||||
guard let sublayers = sublayers else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sublayers.forEach({ layer in
|
|
||||||
if layer.name?.hasPrefix(layerName) ?? false {
|
|
||||||
layer.removeFromSuperlayer()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extension UIView {
|
|
||||||
|
|
||||||
public func addBorder(side: UIRectEdge, width: CGFloat, color: UIColor, offset: CGFloat = 0) {
|
@discardableResult
|
||||||
let layerName = borderLayerName(for: side)
|
public func activate() -> Self{
|
||||||
layer.remove(layerName: layerName)
|
isActive = true
|
||||||
|
return self
|
||||||
let borderLayer = CALayer()
|
|
||||||
borderLayer.backgroundColor = color.cgColor
|
|
||||||
borderLayer.name = layerName
|
|
||||||
|
|
||||||
switch side {
|
|
||||||
case .left:
|
|
||||||
borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: frame.height)
|
|
||||||
case .right:
|
|
||||||
borderLayer.frame = CGRect(x: frame.width - width - offset, y: 0, width: width, height: frame.height)
|
|
||||||
case .top:
|
|
||||||
borderLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: width)
|
|
||||||
case .bottom:
|
|
||||||
borderLayer.frame = CGRect(x: 0, y: frame.height - width - offset, width: frame.width, height: width)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.addSublayer(borderLayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func removeBorders() {
|
|
||||||
layer.borderWidth = 0
|
|
||||||
layer.borderColor = nil
|
|
||||||
layer.remove(layerName: borderLayerName(for: .top))
|
|
||||||
layer.remove(layerName: borderLayerName(for: .left))
|
|
||||||
layer.remove(layerName: borderLayerName(for: .right))
|
|
||||||
layer.remove(layerName: borderLayerName(for: .bottom))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func borderLayerName(for side: UIRectEdge) -> String {
|
@discardableResult
|
||||||
switch side {
|
public func deactivate() -> Self{
|
||||||
case .left:
|
isActive = false
|
||||||
return "leftBorderLayer"
|
return self
|
||||||
case .right:
|
|
||||||
return "rightBorderLayer"
|
|
||||||
case .top:
|
|
||||||
return "topBorderLayer"
|
|
||||||
case .bottom:
|
|
||||||
return "bottomBorderLayer"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Container {
|
||||||
|
public var topConstraint: NSLayoutConstraint?
|
||||||
|
public var leadingConstraint: NSLayoutConstraint?
|
||||||
|
public var trailingConstraint: NSLayoutConstraint?
|
||||||
|
public var bottomConstraint: NSLayoutConstraint?
|
||||||
|
public var widthConstraint: NSLayoutConstraint?
|
||||||
|
public var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
public init(){}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,8 @@
|
|||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"author" : "xcode",
|
||||||
"version" : 1
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,45 +23,230 @@ public enum TextPosition: String, CaseIterable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TextStyle: String, CaseIterable {
|
public struct TextStyle: Equatable {
|
||||||
|
public let rawValue: String
|
||||||
|
public let pointSize: CGFloat
|
||||||
|
public let lineHeight: CGFloat
|
||||||
|
public let letterSpacing: CGFloat
|
||||||
|
public let fontFace: Fonts
|
||||||
|
|
||||||
case featureXLarge
|
public init(rawValue: String, fontFace: Fonts, pointSize: CGFloat, lineHeight: CGFloat, letterSpacing: CGFloat) {
|
||||||
case boldFeatureXLarge
|
self.rawValue = rawValue
|
||||||
case featureLarge
|
self.fontFace = fontFace
|
||||||
case boldFeatureLarge
|
self.pointSize = pointSize
|
||||||
case featureMedium
|
self.lineHeight = lineHeight
|
||||||
case boldFeatureMedium
|
self.letterSpacing = letterSpacing
|
||||||
case featureSmall
|
|
||||||
case boldFeatureSmall
|
|
||||||
case featureXSmall
|
|
||||||
case boldFeatureXSmall
|
|
||||||
|
|
||||||
case title2XLarge
|
|
||||||
case boldTitle2XLarge
|
|
||||||
case titleXLarge
|
|
||||||
case boldTitleXLarge
|
|
||||||
case titleLarge
|
|
||||||
case boldTitleLarge
|
|
||||||
case titleMedium
|
|
||||||
case boldTitleMedium
|
|
||||||
case titleSmall
|
|
||||||
case boldTitleSmall
|
|
||||||
|
|
||||||
case bodyLarge
|
|
||||||
case boldBodyLarge
|
|
||||||
case bodyMedium
|
|
||||||
case boldBodyMedium
|
|
||||||
case bodySmall
|
|
||||||
case boldBodySmall
|
|
||||||
|
|
||||||
case micro
|
|
||||||
case boldMicro
|
|
||||||
|
|
||||||
public static var defaultStyle: TextStyle {
|
|
||||||
return .bodyLarge
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: Definitions
|
||||||
|
extension TextStyle {
|
||||||
|
|
||||||
|
// Static properties for different text styles
|
||||||
|
public static let featureXLarge = TextStyle(rawValue: "featureXLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let featureLarge = TextStyle(rawValue: "featureLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let featureMedium = TextStyle(rawValue: "featureMedium",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let featureSmall = TextStyle(rawValue: "featureSmall",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let featureXSmall = TextStyle(rawValue: "featureXSmall",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let title2XLarge = TextStyle(rawValue: "title2XLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let titleXLarge = TextStyle(rawValue: "titleXLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let titleLarge = TextStyle(rawValue: "titleLarge",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldTitleLarge = TextStyle(rawValue: "boldTitleLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let titleMedium = TextStyle(rawValue: "titleMedium",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldTitleMedium = TextStyle(rawValue: "boldTitleMedium",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let titleSmall = TextStyle(rawValue: "titleSmall",
|
||||||
|
fontFace: .dsLight,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
|
||||||
|
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let bodyLarge = TextStyle(rawValue: "bodyLarge",
|
||||||
|
fontFace: .dsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody16,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody20,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody16,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody20,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static let bodyMedium = TextStyle(rawValue: "bodyMedium",
|
||||||
|
fontFace: .dsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody14,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody18,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody14,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody18,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static let bodySmall = TextStyle(rawValue: "bodySmall",
|
||||||
|
fontFace: .dsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeBody12,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody16,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeBody12,
|
||||||
|
lineHeight: VDSTypography.lineHeightBody16,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static let micro = TextStyle(rawValue: "micro",
|
||||||
|
fontFace: .dsRegular,
|
||||||
|
pointSize: VDSTypography.fontSizeMicro11,
|
||||||
|
lineHeight: VDSTypography.lineHeightMicro16,
|
||||||
|
letterSpacing: 0.25)
|
||||||
|
|
||||||
|
public static let boldMicro = TextStyle(rawValue: "boldMicro",
|
||||||
|
fontFace: .dsBold,
|
||||||
|
pointSize: VDSTypography.fontSizeMicro11,
|
||||||
|
lineHeight: VDSTypography.lineHeightMicro16,
|
||||||
|
letterSpacing: 0.5)
|
||||||
|
|
||||||
|
public static var allCases: [TextStyle] {
|
||||||
|
return [
|
||||||
|
featureXLarge,
|
||||||
|
boldFeatureXLarge,
|
||||||
|
featureLarge,
|
||||||
|
boldFeatureLarge,
|
||||||
|
featureMedium,
|
||||||
|
boldFeatureMedium,
|
||||||
|
featureSmall,
|
||||||
|
boldFeatureSmall,
|
||||||
|
featureXSmall,
|
||||||
|
boldFeatureXSmall,
|
||||||
|
title2XLarge,
|
||||||
|
boldTitle2XLarge,
|
||||||
|
titleXLarge,
|
||||||
|
boldTitleXLarge,
|
||||||
|
titleLarge,
|
||||||
|
boldTitleLarge,
|
||||||
|
titleMedium,
|
||||||
|
boldTitleMedium,
|
||||||
|
titleSmall,
|
||||||
|
boldTitleSmall,
|
||||||
|
bodyLarge,
|
||||||
|
boldBodyLarge,
|
||||||
|
bodyMedium,
|
||||||
|
boldBodyMedium,
|
||||||
|
bodySmall,
|
||||||
|
boldBodySmall,
|
||||||
|
micro,
|
||||||
|
boldMicro
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//MARK: FontCategory
|
//MARK: FontCategory
|
||||||
extension TextStyle {
|
extension TextStyle {
|
||||||
public enum FontCategory: String, CaseIterable {
|
public enum FontCategory: String, CaseIterable {
|
||||||
@ -91,7 +276,8 @@ extension TextStyle {
|
|||||||
} else {
|
} else {
|
||||||
styleName = "\(rawValue)\(fontSize?.rawValue ?? "")"
|
styleName = "\(rawValue)\(fontSize?.rawValue ?? "")"
|
||||||
}
|
}
|
||||||
guard let style = TextStyle(rawValue: styleName) else {
|
|
||||||
|
guard let style = TextStyle.textStyle(for: styleName) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return style
|
return style
|
||||||
@ -111,102 +297,6 @@ extension TextStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: PointSize
|
|
||||||
extension TextStyle {
|
|
||||||
public var pointSize: CGFloat {
|
|
||||||
switch self {
|
|
||||||
case .featureXLarge, .boldFeatureXLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96
|
|
||||||
case .featureLarge, .boldFeatureLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80
|
|
||||||
case .featureMedium, .boldFeatureMedium:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64
|
|
||||||
case .featureSmall, .boldFeatureSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48
|
|
||||||
case .featureXSmall, .boldFeatureXSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40
|
|
||||||
case .title2XLarge, .boldTitle2XLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40
|
|
||||||
case .titleXLarge, .boldTitleXLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32
|
|
||||||
case .titleLarge, .boldTitleLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24
|
|
||||||
case .titleMedium, .boldTitleMedium:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20
|
|
||||||
case .titleSmall, .boldTitleSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16
|
|
||||||
case .bodyLarge, .boldBodyLarge:
|
|
||||||
return VDSTypography.fontSizeBody16
|
|
||||||
case .bodyMedium, .boldBodyMedium:
|
|
||||||
return VDSTypography.fontSizeBody14
|
|
||||||
case .bodySmall, .boldBodySmall:
|
|
||||||
return VDSTypography.fontSizeBody12
|
|
||||||
case .micro, .boldMicro:
|
|
||||||
return VDSTypography.fontSizeMicro11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: LineHeight
|
|
||||||
extension TextStyle {
|
|
||||||
public var lineHeight: CGFloat {
|
|
||||||
switch self {
|
|
||||||
case .featureXLarge, .boldFeatureXLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88
|
|
||||||
case .featureLarge, .boldFeatureLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76
|
|
||||||
case .featureMedium, .boldFeatureMedium:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64
|
|
||||||
case .featureSmall, .boldFeatureSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48
|
|
||||||
case .featureXSmall, .boldFeatureXSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40
|
|
||||||
case .title2XLarge, .boldTitle2XLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40
|
|
||||||
case .titleXLarge, .boldTitleXLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36
|
|
||||||
case .titleLarge, .boldTitleLarge:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28
|
|
||||||
case .titleMedium, .boldTitleMedium:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24
|
|
||||||
case .titleSmall, .boldTitleSmall:
|
|
||||||
return UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20
|
|
||||||
case .bodyLarge, .boldBodyLarge:
|
|
||||||
return VDSTypography.lineHeightBody20
|
|
||||||
case .bodyMedium, .boldBodyMedium:
|
|
||||||
return VDSTypography.lineHeightBody18
|
|
||||||
case .bodySmall, .boldBodySmall:
|
|
||||||
return VDSTypography.lineHeightBody16
|
|
||||||
case .micro, .boldMicro:
|
|
||||||
return VDSTypography.lineHeightMicro16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: LetterSpacing
|
|
||||||
extension TextStyle {
|
|
||||||
public var letterSpacing: CGFloat {
|
|
||||||
switch self {
|
|
||||||
case .featureXLarge,
|
|
||||||
.featureLarge,
|
|
||||||
.featureMedium,
|
|
||||||
.featureSmall,
|
|
||||||
.featureXSmall,
|
|
||||||
.title2XLarge,
|
|
||||||
.titleXLarge,
|
|
||||||
.titleLarge:
|
|
||||||
return 0.25
|
|
||||||
|
|
||||||
case .boldBodyLarge, .bodyLarge,
|
|
||||||
.boldBodyMedium, .bodyMedium:
|
|
||||||
return 0.5
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: Alignments
|
//MARK: Alignments
|
||||||
extension TextStyle {
|
extension TextStyle {
|
||||||
public var aligments: [TextPosition] {
|
public var aligments: [TextPosition] {
|
||||||
@ -216,55 +306,9 @@ extension TextStyle {
|
|||||||
|
|
||||||
//MARK: Fonts
|
//MARK: Fonts
|
||||||
extension TextStyle {
|
extension TextStyle {
|
||||||
public var fontFace: Fonts {
|
|
||||||
switch self {
|
|
||||||
case .boldFeatureXLarge,
|
|
||||||
.boldFeatureLarge,
|
|
||||||
.boldFeatureMedium,
|
|
||||||
.boldFeatureSmall,
|
|
||||||
.boldFeatureXSmall,
|
|
||||||
.boldTitle2XLarge,
|
|
||||||
.boldTitleXLarge,
|
|
||||||
.boldTitleLarge,
|
|
||||||
.boldTitleMedium,
|
|
||||||
.boldTitleSmall,
|
|
||||||
.boldBodyLarge,
|
|
||||||
.boldBodyMedium:
|
|
||||||
return .dsBold
|
|
||||||
|
|
||||||
case .featureXLarge,
|
|
||||||
.featureLarge,
|
|
||||||
.featureMedium,
|
|
||||||
.featureSmall,
|
|
||||||
.featureXSmall,
|
|
||||||
.title2XLarge,
|
|
||||||
.titleXLarge:
|
|
||||||
return .dsLight
|
|
||||||
|
|
||||||
case .titleLarge,
|
|
||||||
.titleMedium,
|
|
||||||
.titleSmall,
|
|
||||||
.bodyLarge,
|
|
||||||
.bodyMedium:
|
|
||||||
return .dsRegular
|
|
||||||
|
|
||||||
case .boldBodySmall,
|
|
||||||
.boldMicro:
|
|
||||||
return .txBold
|
|
||||||
|
|
||||||
case .bodySmall,
|
|
||||||
.micro:
|
|
||||||
return .txRegular
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var font: UIFont {
|
public var font: UIFont {
|
||||||
return fontFace.font(ofSize: pointSize)
|
return fontFace.font(ofSize: pointSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var superScriptFont: UIFont {
|
|
||||||
return fontFace.font(ofSize: pointSize / 2)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextStyle {
|
extension TextStyle {
|
||||||
@ -335,3 +379,12 @@ extension TextStyle: CustomDebugStringConvertible {
|
|||||||
"Name: \(self.rawValue) FontFace: \(font.fontName) FontWeight: \(self.rawValue.hasPrefix("bold") ? "bold" : "normal") PointSize: \(font.pointSize) LetterSpacing: \(letterSpacing) LineHeight: \(lineHeight)"
|
"Name: \(self.rawValue) FontFace: \(font.fontName) FontWeight: \(self.rawValue.hasPrefix("bold") ? "bold" : "normal") PointSize: \(font.pointSize) LetterSpacing: \(letterSpacing) LineHeight: \(lineHeight)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TextStyle {
|
||||||
|
public static var defaultStyle: TextStyle { return bodyLarge }
|
||||||
|
|
||||||
|
public static func textStyle(for name: String) -> TextStyle? {
|
||||||
|
guard let style = TextStyle.allCases.first(where: {$0.rawValue == name }) else { return nil }
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user