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 */; };
|
||||
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.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 */; };
|
||||
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -394,6 +402,7 @@
|
||||
EA33619D288B1E330071C351 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAD062AE2A3B87210015965D /* BadgeIndicator */,
|
||||
EA4DB2FE28DCBC1900103EE3 /* Badge */,
|
||||
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
||||
EAF7F092289985E200B287F5 /* Checkbox */,
|
||||
@ -429,12 +438,15 @@
|
||||
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
|
||||
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
|
||||
EABFEB632A26473700C4C106 /* NSAttributedString.swift */,
|
||||
EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */,
|
||||
EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */,
|
||||
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
|
||||
EA3361A7288B23300071C351 /* UIColor.swift */,
|
||||
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
|
||||
EA33623D2892EE950071C351 /* UIDevice.swift */,
|
||||
EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */,
|
||||
EAB5FED329267EB300998C17 /* UIView.swift */,
|
||||
EAD062A62A3B67770015965D /* UIView+CALayer.swift */,
|
||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
|
||||
EA985C662970C21600F2FF2E /* VDSLayout.swift */,
|
||||
);
|
||||
@ -686,6 +698,14 @@
|
||||
path = EntryField;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAD062AE2A3B87210015965D /* BadgeIndicator */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */,
|
||||
);
|
||||
path = BadgeIndicator;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAF7F092289985E200B287F5 /* Checkbox */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -884,6 +904,7 @@
|
||||
EA33624728931B050071C351 /* Initable.swift in Sources */,
|
||||
EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */,
|
||||
EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */,
|
||||
EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */,
|
||||
EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */,
|
||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */,
|
||||
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */,
|
||||
@ -917,6 +938,7 @@
|
||||
EA336171288B19200071C351 /* VDS.docc in Sources */,
|
||||
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
||||
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
||||
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
|
||||
@ -927,6 +949,7 @@
|
||||
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
|
||||
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
|
||||
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
||||
EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */,
|
||||
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
||||
EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */,
|
||||
EA985C672970C21600F2FF2E /* VDSLayout.swift in Sources */,
|
||||
@ -941,6 +964,7 @@
|
||||
EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */,
|
||||
EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */,
|
||||
EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */,
|
||||
EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */,
|
||||
EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.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()
|
||||
}()
|
||||
var shadowColorConfiguration: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||
SurfaceColorConfiguration(VDSColor.paletteBlack, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
var shadowOpacity: CGFloat = 0.5
|
||||
var shadowOffset: CGSize = .init(width: 1, height: 1)
|
||||
var shadowOpacity: CGFloat = 0.16
|
||||
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
||||
var shadowRadius: CGFloat = 2
|
||||
}
|
||||
|
||||
|
||||
private struct HighContrastConfiguration: Configuration {
|
||||
var kind: Kind = .highContrast
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
@ -280,7 +280,6 @@ open class ButtonIcon: Control {
|
||||
} else {
|
||||
icon.reset()
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
@ -316,26 +315,15 @@ open class ButtonIcon: Control {
|
||||
if let borderable = currentConfig as? Borderable {
|
||||
layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor
|
||||
layer.borderWidth = borderable.borderWidth
|
||||
icon.layer.borderWidth = borderable.borderWidth
|
||||
} else {
|
||||
layer.borderColor = nil
|
||||
layer.borderWidth = 0
|
||||
icon.layer.borderWidth = 0
|
||||
}
|
||||
|
||||
if let dropshadowable = currentConfig as? Dropshadowable {
|
||||
layer.masksToBounds = false
|
||||
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
|
||||
addDropShadow(config: dropshadowable)
|
||||
} else {
|
||||
layer.shadowOpacity = 0
|
||||
layer.shadowRadius = 0
|
||||
layer.shadowPath = nil
|
||||
removeDropShadow()
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 {
|
||||
var borderWidth: CGFloat { 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 edgeInset: UIEdgeInsets = .zero {
|
||||
didSet {
|
||||
setNeedsUpdate()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override open var text: String? {
|
||||
didSet {
|
||||
attributes = nil
|
||||
@ -192,7 +200,16 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
||||
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
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -11,7 +11,7 @@ extension TitleLockup {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
public enum TitleTextStyle: String, EnumSubset {
|
||||
public enum TitleTextStyle: String, CaseIterable {
|
||||
|
||||
case featureMedium
|
||||
case boldFeatureMedium
|
||||
@ -32,9 +32,14 @@ extension TitleLockup {
|
||||
case boldTitleSmall
|
||||
|
||||
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 boldBodyLarge
|
||||
case bodyMedium
|
||||
@ -43,6 +48,9 @@ extension TitleLockup {
|
||||
case boldBodySmall
|
||||
|
||||
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}
|
||||
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
|
||||
|
||||
extension UIView {
|
||||
public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) {
|
||||
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edges.left).isActive = true
|
||||
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -edges.right).isActive = true
|
||||
topAnchor.constraint(equalTo: view.topAnchor, constant: edges.top).isActive = true
|
||||
bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -edges.bottom).isActive = true
|
||||
|
||||
public func constraint(with identifier: String) -> NSLayoutConstraint? {
|
||||
return constraints.first { $0.identifier == identifier }
|
||||
}
|
||||
|
||||
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 {
|
||||
pin(superview, with: edges)
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - HeightAnchor
|
||||
//--------------------------------------------------
|
||||
extension UIView {
|
||||
|
||||
@discardableResult
|
||||
public func height(_ constant: CGFloat) -> Self {
|
||||
heightAnchor.constraint(equalToConstant: constant).isActive = true
|
||||
height(constant: constant)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func heightGreaterThanEqual(_ constant: CGFloat) -> Self {
|
||||
heightAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true
|
||||
public func heightGreaterThanEqualTo(_ constant: CGFloat) -> Self {
|
||||
heightGreaterThanEqualTo(constant: constant)
|
||||
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
|
||||
public func widthGreaterThanEqual(_ constant: CGFloat) -> Self {
|
||||
widthAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true
|
||||
public func heightLessThanEqualTo(_ constant: CGFloat) -> Self {
|
||||
heightLessThanEqualTo(constant: constant)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func height(constant: CGFloat) -> NSLayoutConstraint {
|
||||
heightAnchor.constraint(equalToConstant: constant).activate()
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func widthLessThanEqual(_ constant: CGFloat) -> Self {
|
||||
widthAnchor.constraint(lessThanOrEqualToConstant: constant).isActive = true
|
||||
public func heightGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint {
|
||||
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
|
||||
}
|
||||
|
||||
@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
|
||||
public func pinTop(_ constant: CGFloat = 0.0) -> Self {
|
||||
return pinTop(nil, constant)
|
||||
@ -67,13 +129,49 @@ extension UIView {
|
||||
|
||||
@discardableResult
|
||||
public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor
|
||||
if let found {
|
||||
topAnchor.constraint(equalTo: found, constant: constant).isActive = true
|
||||
}
|
||||
pinTop(anchor: anchor, constant: constant)
|
||||
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
|
||||
public func pinBottom(_ constant: CGFloat = 0.0) -> Self {
|
||||
return pinBottom(nil, constant)
|
||||
@ -81,161 +179,167 @@ extension UIView {
|
||||
|
||||
@discardableResult
|
||||
public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor
|
||||
if let found {
|
||||
bottomAnchor.constraint(equalTo: found, constant: -constant).isActive = true
|
||||
}
|
||||
pinBottom(anchor: anchor, constant: constant)
|
||||
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
|
||||
public func pinLeading(_ constant: CGFloat = 0.0) -> Self {
|
||||
return pinLeading(nil, constant)
|
||||
}
|
||||
|
||||
|
||||
@discardableResult
|
||||
public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor
|
||||
if let found {
|
||||
leadingAnchor.constraint(equalTo: found, constant: constant).isActive = true
|
||||
}
|
||||
pinLeading(anchor: anchor, constant: constant)
|
||||
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
|
||||
public func pinTrailing(_ constant: CGFloat = 0.0) -> Self {
|
||||
return pinTrailing(nil, constant)
|
||||
pinTrailing(nil, constant)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
|
||||
if let found {
|
||||
trailingAnchor.constraint(equalTo: found, constant: -constant).isActive = true
|
||||
}
|
||||
pinTrailing(anchor: anchor, constant: constant)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
|
||||
pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant)
|
||||
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 {
|
||||
|
||||
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()
|
||||
}
|
||||
@discardableResult
|
||||
public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? {
|
||||
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
|
||||
guard let found else { return nil }
|
||||
return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate()
|
||||
}
|
||||
}
|
||||
|
||||
extension CALayer {
|
||||
func remove(layerName: String) {
|
||||
guard let sublayers = sublayers else {
|
||||
return
|
||||
}
|
||||
|
||||
sublayers.forEach({ layer in
|
||||
if layer.name?.hasPrefix(layerName) ?? false {
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension UIView {
|
||||
extension NSLayoutConstraint {
|
||||
|
||||
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))
|
||||
@discardableResult
|
||||
public func activate() -> Self{
|
||||
isActive = true
|
||||
return self
|
||||
}
|
||||
|
||||
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 ""
|
||||
}
|
||||
@discardableResult
|
||||
public func deactivate() -> Self{
|
||||
isActive = false
|
||||
return self
|
||||
}
|
||||
|
||||
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" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"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
|
||||
case boldFeatureXLarge
|
||||
case featureLarge
|
||||
case boldFeatureLarge
|
||||
case featureMedium
|
||||
case boldFeatureMedium
|
||||
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
|
||||
public init(rawValue: String, fontFace: Fonts, pointSize: CGFloat, lineHeight: CGFloat, letterSpacing: CGFloat) {
|
||||
self.rawValue = rawValue
|
||||
self.fontFace = fontFace
|
||||
self.pointSize = pointSize
|
||||
self.lineHeight = lineHeight
|
||||
self.letterSpacing = letterSpacing
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
extension TextStyle {
|
||||
public enum FontCategory: String, CaseIterable {
|
||||
@ -91,7 +276,8 @@ extension TextStyle {
|
||||
} else {
|
||||
styleName = "\(rawValue)\(fontSize?.rawValue ?? "")"
|
||||
}
|
||||
guard let style = TextStyle(rawValue: styleName) else {
|
||||
|
||||
guard let style = TextStyle.textStyle(for: styleName) else {
|
||||
return nil
|
||||
}
|
||||
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
|
||||
extension TextStyle {
|
||||
public var aligments: [TextPosition] {
|
||||
@ -216,55 +306,9 @@ extension TextStyle {
|
||||
|
||||
//MARK: Fonts
|
||||
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 {
|
||||
return fontFace.font(ofSize: pointSize)
|
||||
}
|
||||
|
||||
public var superScriptFont: UIFont {
|
||||
return fontFace.font(ofSize: pointSize / 2)
|
||||
}
|
||||
}
|
||||
|
||||
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)"
|
||||
}
|
||||
}
|
||||
|
||||
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