Merge branch 'feature/tilet' into 'develop'
added tileContainer and extension for VDSColor See merge request BPHV_MIPS/vds_ios!22
This commit is contained in:
commit
9a8d512403
@ -40,6 +40,11 @@
|
||||
EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */; };
|
||||
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */; };
|
||||
EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB30128DCBCA500103EE3 /* Badge.swift */; };
|
||||
EA5E304C294CBDD00082B959 /* TileContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E304B294CBDD00082B959 /* TileContainer.swift */; };
|
||||
EA5E304E294CC7F00082B959 /* VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E304D294CC7F00082B959 /* VDSColor.swift */; };
|
||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30522950DDA60082B959 /* TitleLockup.swift */; };
|
||||
EA5E3058295105A40082B959 /* Tilet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilet.swift */; };
|
||||
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; };
|
||||
EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */; };
|
||||
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; };
|
||||
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; };
|
||||
@ -135,6 +140,11 @@
|
||||
EA4DB18428CA967F00103EE3 /* SelectorGroupHandlerBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorGroupHandlerBase.swift; sourceTree = "<group>"; };
|
||||
EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEquatable.swift; sourceTree = "<group>"; };
|
||||
EA4DB30128DCBCA500103EE3 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = "<group>"; };
|
||||
EA5E304B294CBDD00082B959 /* TileContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainer.swift; sourceTree = "<group>"; };
|
||||
EA5E304D294CC7F00082B959 /* VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSColor.swift; sourceTree = "<group>"; };
|
||||
EA5E30522950DDA60082B959 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
|
||||
EA5E3057295105A40082B959 /* Tilet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilet.swift; sourceTree = "<group>"; };
|
||||
EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = "<group>"; };
|
||||
EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Publisher.swift"; sourceTree = "<group>"; };
|
||||
EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = "<group>"; };
|
||||
EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = "<group>"; };
|
||||
@ -313,6 +323,9 @@
|
||||
EAF7F11428A1470D00B287F5 /* RadioButton */,
|
||||
EA1F265F28B945070033E859 /* RadioSwatch */,
|
||||
EAC925852911C9DE00091998 /* TextFields */,
|
||||
EA5E304A294CBDBB0082B959 /* TileContainer */,
|
||||
EA5E3056295105930082B959 /* Tilet */,
|
||||
EA5E30512950DD8D0082B959 /* TitleLockup */,
|
||||
EA3361A0288B1E6F0071C351 /* Toggle */,
|
||||
);
|
||||
path = Components;
|
||||
@ -337,6 +350,7 @@
|
||||
EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */,
|
||||
EAB5FED329267EB300998C17 /* UIView.swift */,
|
||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
|
||||
EA5E304D294CC7F00082B959 /* VDSColor.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -349,6 +363,7 @@
|
||||
EAA5EEDF28F49DB3003B3210 /* Colorable.swift */,
|
||||
EA3361AC288B26190071C351 /* DataTrackable.swift */,
|
||||
EA3361A9288B25E40071C351 /* Disabling.swift */,
|
||||
EA5E305929510F8B0082B959 /* EnumSubset.swift */,
|
||||
EAF7F0A1289AFB3900B287F5 /* Errorable.swift */,
|
||||
EA3361AE288B26310071C351 /* FormFieldable.swift */,
|
||||
EA3361BE288B2EA60071C351 /* Handlerable.swift */,
|
||||
@ -430,6 +445,30 @@
|
||||
path = Badge;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA5E304A294CBDBB0082B959 /* TileContainer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA5E304B294CBDD00082B959 /* TileContainer.swift */,
|
||||
);
|
||||
path = TileContainer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA5E30512950DD8D0082B959 /* TitleLockup */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA5E30522950DDA60082B959 /* TitleLockup.swift */,
|
||||
);
|
||||
path = TitleLockup;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA5E3056295105930082B959 /* Tilet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA5E3057295105A40082B959 /* Tilet.swift */,
|
||||
);
|
||||
path = Tilet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA89200B28B530F0006B9984 /* RadioBox */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -651,6 +690,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EAF7F0B5289C126F00B287F5 /* UILabel.swift in Sources */,
|
||||
EA5E304C294CBDD00082B959 /* TileContainer.swift in Sources */,
|
||||
EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */,
|
||||
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */,
|
||||
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
|
||||
@ -663,6 +703,7 @@
|
||||
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
||||
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
|
||||
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */,
|
||||
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */,
|
||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||
EA3361C5289030FC0071C351 /* Accessable.swift in Sources */,
|
||||
@ -692,6 +733,8 @@
|
||||
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
|
||||
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */,
|
||||
EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */,
|
||||
EA5E3058295105A40082B959 /* Tilet.swift in Sources */,
|
||||
EA5E304E294CC7F00082B959 /* VDSColor.swift in Sources */,
|
||||
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
|
||||
EAF7F09E289AAEC000B287F5 /* Constants.swift in Sources */,
|
||||
EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */,
|
||||
@ -700,6 +743,7 @@
|
||||
EAF7F0AB289B13FD00B287F5 /* TypographicalStyleLabelAttribute.swift in Sources */,
|
||||
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */,
|
||||
EA336171288B19200071C351 /* VDS.docc in Sources */,
|
||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
||||
EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */,
|
||||
|
||||
@ -29,10 +29,12 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable {
|
||||
|
||||
open override var isSelected: Bool { didSet { didChange() } }
|
||||
|
||||
internal var enabledHighlight: Bool = true
|
||||
|
||||
var isHighlightAnimating = false
|
||||
open override var isHighlighted: Bool {
|
||||
didSet {
|
||||
if isHighlightAnimating == false {
|
||||
if isHighlightAnimating == false && enabledHighlight {
|
||||
isHighlightAnimating = true
|
||||
UIView.animate(withDuration: 0.1, animations: { [weak self] in
|
||||
self?.updateView()
|
||||
|
||||
@ -124,6 +124,10 @@ public class RadioSwatchGroupBase<HandlerType: RadioSwatchBase>: SelectorGroupSe
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
public func reload() {
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - UICollectionViewDelegateFlowLayout
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -163,10 +163,10 @@ open class EntryField: Control, Accessable {
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
enabledHighlight = false
|
||||
isAccessibilityElement = true
|
||||
accessibilityTraits = .button
|
||||
addSubview(stackView)
|
||||
stackView.isUserInteractionEnabled = false
|
||||
|
||||
//create the wrapping view
|
||||
heightConstraint = containerView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height)
|
||||
@ -184,8 +184,12 @@ open class EntryField: Control, Accessable {
|
||||
stackView.setCustomSpacing(8, after: container)
|
||||
stackView.setCustomSpacing(8, after: errorLabel)
|
||||
|
||||
stackView.pinToSuperView()
|
||||
|
||||
stackView
|
||||
.pinTop()
|
||||
.pinBottom()
|
||||
.pinLeading()
|
||||
.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor).isActive = true
|
||||
|
||||
titleLabel.textColorConfiguration = primaryColorConfig.eraseToAnyColorable()
|
||||
errorLabel.textColorConfiguration = primaryColorConfig.eraseToAnyColorable()
|
||||
helperLabel.textColorConfiguration = secondaryColorConfig.eraseToAnyColorable()
|
||||
|
||||
316
VDS/Components/TileContainer/TileContainer.swift
Normal file
316
VDS/Components/TileContainer/TileContainer.swift
Normal file
@ -0,0 +1,316 @@
|
||||
//
|
||||
// TileContainer.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 12/16/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
import UIKit
|
||||
|
||||
@objc(VDSTileContainer)
|
||||
open class TileContainer: Control {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public enum ContainerBackgroundColor: String, CaseIterable {
|
||||
case white
|
||||
case black
|
||||
case gray
|
||||
case transparent
|
||||
}
|
||||
|
||||
public enum ContainerPadding: String, CaseIterable {
|
||||
case twelve = "12"
|
||||
case sixteen = "16"
|
||||
case twentyFour = "24"
|
||||
case thirtyTwo = "32"
|
||||
case fourtyEight = "48"
|
||||
}
|
||||
|
||||
public enum ContainerScalingType: String, CaseIterable {
|
||||
case ratio1x1 = "1:1"
|
||||
case ratio3x4 = "3:4"
|
||||
case ratio4x3 = "4:3"
|
||||
case ratio2x3 = "2:3"
|
||||
case ratio3x2 = "3:2"
|
||||
case ratio9x16 = "9:16"
|
||||
case ratio16x9 = "16:9"
|
||||
case ratio1x2 = "1:2"
|
||||
case ratio2x1 = "2:1"
|
||||
case none
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var backgroundImage: UIImage? { didSet{ didChange() } }
|
||||
|
||||
public var containerView = View()
|
||||
|
||||
public var highlightView = View()
|
||||
|
||||
public var containerBackgroundColor: ContainerBackgroundColor = .white { didSet{ didChange() } }
|
||||
|
||||
public var containerPadding: ContainerPadding = .sixteen { didSet{ didChange() } }
|
||||
|
||||
public var aspectRatio: ContainerScalingType = .ratio1x1 { didSet{ didChange() } }
|
||||
|
||||
public var imageFallbackColor: Surface = .light { didSet{ didChange() } }
|
||||
|
||||
private var _width: CGFloat = 100
|
||||
public var width: CGFloat {
|
||||
get { return _width }
|
||||
set {
|
||||
if newValue > 100 {
|
||||
_width = newValue
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _height: CGFloat?
|
||||
public var height: CGFloat? {
|
||||
get { return _height }
|
||||
set {
|
||||
if let newValue, newValue > 44 {
|
||||
_height = newValue
|
||||
} else {
|
||||
_height = nil
|
||||
}
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
public var showBorder: Bool = false { didSet{ didChange() } }
|
||||
|
||||
public var showDropShadows: Bool = false { didSet{ didChange() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var backgroundImageView = UIImageView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.contentMode = .scaleAspectFill
|
||||
$0.clipsToBounds = true
|
||||
}
|
||||
|
||||
internal var padding: CGFloat {
|
||||
switch containerPadding {
|
||||
case .twelve:
|
||||
return 12.0
|
||||
case .sixteen:
|
||||
return 16.0
|
||||
case .twentyFour:
|
||||
return 24.0
|
||||
case .thirtyTwo:
|
||||
return 32.0
|
||||
case .fourtyEight:
|
||||
return 48.0
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var widthConstraint: NSLayoutConstraint?
|
||||
internal var heightConstraint: NSLayoutConstraint?
|
||||
internal var heightGreaterThanConstraint: NSLayoutConstraint?
|
||||
internal var containerTopConstraint: NSLayoutConstraint?
|
||||
internal var containerBottomConstraint: NSLayoutConstraint?
|
||||
internal var containerLeadingConstraint: NSLayoutConstraint?
|
||||
internal var containerTrailingConstraint: NSLayoutConstraint?
|
||||
|
||||
//functions
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
addSubview(backgroundImageView)
|
||||
addSubview(containerView)
|
||||
addSubview(highlightView)
|
||||
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: width)
|
||||
widthConstraint?.isActive = true
|
||||
|
||||
heightGreaterThanConstraint = heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0)
|
||||
heightGreaterThanConstraint?.isActive = false
|
||||
|
||||
heightConstraint = heightAnchor.constraint(equalToConstant: width)
|
||||
heightConstraint?.isActive = true
|
||||
|
||||
backgroundImageView.pinToSuperView()
|
||||
backgroundImageView.isUserInteractionEnabled = false
|
||||
backgroundImageView.isHidden = true
|
||||
|
||||
containerView.isUserInteractionEnabled = false
|
||||
containerView.backgroundColor = .clear
|
||||
|
||||
containerTopConstraint = containerView.topAnchor.constraint(equalTo: topAnchor, constant: padding)
|
||||
containerTopConstraint?.isActive = true
|
||||
containerBottomConstraint = containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: padding)
|
||||
containerBottomConstraint?.isActive = true
|
||||
containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding)
|
||||
containerLeadingConstraint?.isActive = true
|
||||
containerTrailingConstraint = containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: padding)
|
||||
containerTrailingConstraint?.isActive = true
|
||||
|
||||
highlightView.pinToSuperView()
|
||||
highlightView.isUserInteractionEnabled = false
|
||||
highlightView.isHidden = true
|
||||
highlightView.backgroundColor = .clear
|
||||
|
||||
//corner radius
|
||||
layer.cornerRadius = cornerRadius
|
||||
backgroundImageView.layer.cornerRadius = 8
|
||||
highlightView.layer.cornerRadius = 8
|
||||
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration
|
||||
//--------------------------------------------------
|
||||
private let cornerRadius = 8.0
|
||||
|
||||
private var backgroundColorConfig = BackgroundColorConfiguration()
|
||||
|
||||
private var borderColorConfig = SurfaceColorConfiguration().with {
|
||||
$0.lightColor = VDSColor.elementsLowContrastOnLight
|
||||
$0.darkColor = VDSColor.elementsLowContrastOnDark
|
||||
}
|
||||
|
||||
private var imageFallbackColorConfig = SurfaceColorConfiguration().with {
|
||||
$0.lightColor = VDSColor.backgroundPrimaryLight
|
||||
$0.darkColor = VDSColor.backgroundPrimaryDark
|
||||
}
|
||||
|
||||
private var hightLightViewColorConfig = SurfaceColorConfiguration().with {
|
||||
$0.lightColor = VDSColor.paletteWhite.withAlphaComponent(0.3)
|
||||
$0.darkColor = VDSColor.paletteBlack.withAlphaComponent(0.3)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - State
|
||||
//--------------------------------------------------
|
||||
var ratioSize: CGSize {
|
||||
var height: CGFloat = width
|
||||
|
||||
switch aspectRatio {
|
||||
case .ratio1x1:
|
||||
break;
|
||||
case .ratio3x4:
|
||||
height = (4 / 3) * width
|
||||
case .ratio4x3:
|
||||
height = (3 / 4) * width
|
||||
case .ratio2x3:
|
||||
height = (3 / 2) * width
|
||||
case .ratio3x2:
|
||||
height = (2 / 3) * width
|
||||
case .ratio9x16:
|
||||
height = (16 / 9) * width
|
||||
case .ratio16x9:
|
||||
height = (9 / 16) * width
|
||||
case .ratio1x2:
|
||||
height = (2 / 1) * width
|
||||
case .ratio2x1:
|
||||
height = (1 / 2) * width
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
highlightView.backgroundColor = hightLightViewColorConfig.getColor(self)
|
||||
highlightView.isHidden = !isHighlighted
|
||||
|
||||
if let backgroundImage {
|
||||
backgroundImageView.image = backgroundImage
|
||||
backgroundImageView.isHidden = false
|
||||
backgroundColor = imageFallbackColorConfig.getColor(self)
|
||||
} else {
|
||||
backgroundImageView.isHidden = true
|
||||
backgroundColor = backgroundColorConfig.getColor(self)
|
||||
}
|
||||
|
||||
layer.borderColor = borderColorConfig.getColor(self).cgColor
|
||||
layer.borderWidth = showBorder ? 1 : 0
|
||||
|
||||
containerTopConstraint?.constant = padding
|
||||
containerLeadingConstraint?.constant = padding
|
||||
containerBottomConstraint?.constant = -padding
|
||||
containerTrailingConstraint?.constant = -padding
|
||||
|
||||
if aspectRatio == .none {
|
||||
widthConstraint?.constant = width
|
||||
heightConstraint?.isActive = false
|
||||
heightGreaterThanConstraint?.isActive = true
|
||||
} else if let height {
|
||||
widthConstraint?.constant = width
|
||||
heightConstraint?.constant = height
|
||||
heightConstraint?.isActive = true
|
||||
heightGreaterThanConstraint?.isActive = false
|
||||
} else {
|
||||
let size = ratioSize
|
||||
widthConstraint?.constant = size.width
|
||||
heightConstraint?.constant = size.height
|
||||
heightConstraint?.isActive = true
|
||||
heightGreaterThanConstraint?.isActive = false
|
||||
}
|
||||
}
|
||||
|
||||
public func addContentView(_ view: UIView, shouldPin: Bool = true) {
|
||||
containerView.addSubview(view)
|
||||
if shouldPin {
|
||||
view.pinToSuperView()
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundColorConfiguration: ObjectColorable {
|
||||
typealias ObjectType = TileContainer
|
||||
|
||||
required init() { }
|
||||
|
||||
func getColor(_ object: TileContainer) -> UIColor {
|
||||
switch object.containerBackgroundColor {
|
||||
|
||||
case .white:
|
||||
return VDSColor.backgroundPrimaryLight
|
||||
case .black:
|
||||
return VDSColor.backgroundPrimaryDark
|
||||
case .gray:
|
||||
return VDSColor.backgroundSecondaryLight
|
||||
case .transparent:
|
||||
return UIColor.clear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
208
VDS/Components/Tilet/Tilet.swift
Normal file
208
VDS/Components/Tilet/Tilet.swift
Normal file
@ -0,0 +1,208 @@
|
||||
//
|
||||
// Tilet.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 12/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
import UIKit
|
||||
|
||||
public enum TiletTitleTypographicalStyle: String, Codable, EnumSubset {
|
||||
case TitleXLarge
|
||||
case BoldTitleXLarge
|
||||
case TitleLarge
|
||||
case BoldTitleLarge
|
||||
case TitleMedium
|
||||
case BoldTitleMedium
|
||||
case TitleSmall
|
||||
case BoldTitleSmall
|
||||
|
||||
public var defaultValue: TitleLockupTitleTypographicalStyle { .BoldTitleSmall }
|
||||
}
|
||||
|
||||
public enum TiletOtherTypographicalStyle: String, Codable, EnumSubset {
|
||||
case BodyLarge
|
||||
case BoldBodyLarge
|
||||
case BodyMedium
|
||||
case BoldBodyMedium
|
||||
case BodySmall
|
||||
case BoldBodySmall
|
||||
|
||||
public var defaultValue: TitleLockupOtherTypographicalStyle { .BodySmall }
|
||||
}
|
||||
|
||||
|
||||
@objc(VDSTilet)
|
||||
open class Tilet: View {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
initialSetup()
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var tileContainer = TileContainer().with {
|
||||
$0.aspectRatio = .none
|
||||
$0.surface = .light
|
||||
}
|
||||
|
||||
private var titleLockup = TitleLockup()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
//style
|
||||
open var titleTypograpicalStyle: TiletTitleTypographicalStyle = .BoldTitleSmall { didSet { didChange() }}
|
||||
open var otherTypograpicalStyle: TiletOtherTypographicalStyle = .BodySmall { didSet { didChange() }}
|
||||
|
||||
open var width: CGFloat = 100 { didSet { didChange() }}
|
||||
|
||||
private var _textWidth: CGFloat?
|
||||
open var textWidth: CGFloat? {
|
||||
get { _textWidth }
|
||||
set {
|
||||
if let newValue, newValue > 44.0 && newValue <= width {
|
||||
_textWidth = newValue
|
||||
if _textPercentage != nil {
|
||||
_textPercentage = nil
|
||||
}
|
||||
} else {
|
||||
_textWidth = nil
|
||||
}
|
||||
didChange()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var _textPercentage: CGFloat?
|
||||
open var textPercentage: CGFloat? {
|
||||
get { _textPercentage }
|
||||
set {
|
||||
if let newValue, newValue >= 5 && newValue <= 100.0 {
|
||||
_textPercentage = newValue
|
||||
if textWidth != nil {
|
||||
_textWidth = nil
|
||||
}
|
||||
} else {
|
||||
_textPercentage = nil
|
||||
}
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
//text
|
||||
open var titleText: String = "" { didSet { didChange() }}
|
||||
open var titleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
open var subTitleText: String = "" { didSet { didChange() }}
|
||||
open var subTitleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
open var subTitleColor: Use = .primary { didSet { didChange() }}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var titleLockupWidthConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupTrailingConstraint: NSLayoutConstraint?
|
||||
//functions
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
addSubview(tileContainer)
|
||||
tileContainer.pinToSuperView()
|
||||
tileContainer.addContentView(titleLockup, shouldPin: false)
|
||||
titleLockup.pinTop()
|
||||
titleLockup.pinLeading()
|
||||
titleLockup.pinBottom()
|
||||
|
||||
//either you are 100% width of the tileContainer.contentView
|
||||
titleLockupTrailingConstraint = titleLockup.trailingAnchor.constraint(equalTo: tileContainer.containerView.trailingAnchor)
|
||||
titleLockupTrailingConstraint?.isActive = true
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
tileContainer.reset()
|
||||
tileContainer.aspectRatio = .none
|
||||
tileContainer.surface = .light
|
||||
|
||||
titleLockup.reset()
|
||||
|
||||
titleText = ""
|
||||
titleTextAttributes = nil
|
||||
subTitleText = ""
|
||||
subTitleTextAttributes = nil
|
||||
subTitleColor = .primary
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - State
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
//flip the color
|
||||
let flippedColor:TileContainer.ContainerBackgroundColor = surface == .dark ? .white : .black
|
||||
tileContainer.containerBackgroundColor = flippedColor
|
||||
tileContainer.width = width
|
||||
|
||||
//flip the surface for the titleLockup
|
||||
let flippedSurface: Surface = surface == .dark ? .light : .dark
|
||||
titleLockup.surface = flippedSurface
|
||||
|
||||
//either use textWidth
|
||||
if let textWidth {
|
||||
titleLockupTrailingConstraint?.isActive = false
|
||||
titleLockupWidthConstraint?.isActive = false
|
||||
titleLockupWidthConstraint = titleLockup.widthAnchor.constraint(equalToConstant: textWidth)
|
||||
titleLockupWidthConstraint?.isActive = true
|
||||
|
||||
} else if let textPercentage {
|
||||
titleLockupTrailingConstraint?.isActive = false
|
||||
titleLockupWidthConstraint?.isActive = false
|
||||
titleLockupWidthConstraint = NSLayoutConstraint(item: titleLockup,
|
||||
attribute: .width,
|
||||
relatedBy: .equal,
|
||||
toItem: tileContainer.containerView,
|
||||
attribute: .width,
|
||||
multiplier: textPercentage / 100,
|
||||
constant: 0.0)
|
||||
titleLockupWidthConstraint?.isActive = true
|
||||
|
||||
} else {
|
||||
titleLockupWidthConstraint?.isActive = false
|
||||
titleLockupTrailingConstraint?.isActive = true
|
||||
|
||||
}
|
||||
|
||||
titleLockup.titleText = titleText
|
||||
titleLockup.titleTypograpicalStyle = titleTypograpicalStyle.value
|
||||
titleLockup.titleTextAttributes = titleTextAttributes
|
||||
|
||||
titleLockup.subTitleText = subTitleText
|
||||
titleLockup.otherTypograpicalStyle = otherTypograpicalStyle.value
|
||||
titleLockup.subTitleTextAttributes = titleTextAttributes
|
||||
titleLockup.subTitleColor = subTitleColor
|
||||
}
|
||||
}
|
||||
337
VDS/Components/TitleLockup/TitleLockup.swift
Normal file
337
VDS/Components/TitleLockup/TitleLockup.swift
Normal file
@ -0,0 +1,337 @@
|
||||
//
|
||||
// TitleLockup.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 12/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
import Combine
|
||||
|
||||
public enum TitleLockupTextPosition: String, Codable, CaseIterable {
|
||||
case left, center
|
||||
|
||||
var labelTextPosition: TextPosition {
|
||||
switch self {
|
||||
case .left:
|
||||
return .left
|
||||
case .center:
|
||||
return .center
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TitleLockupTitleTypographicalStyle: String, Codable, EnumSubset {
|
||||
|
||||
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
|
||||
|
||||
public var defaultValue: TypographicalStyle {.BoldFeatureXSmall }
|
||||
}
|
||||
|
||||
public enum TitleLockupOtherTypographicalStyle: String, Codable, EnumSubset {
|
||||
case BodyLarge
|
||||
case BoldBodyLarge
|
||||
case BodyMedium
|
||||
case BoldBodyMedium
|
||||
case BodySmall
|
||||
case BoldBodySmall
|
||||
|
||||
public var defaultValue: TypographicalStyle {.BodyLarge }
|
||||
}
|
||||
|
||||
@objc(VDSTitleLockup)
|
||||
open class TitleLockup: View {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var stackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
$0.distribution = .fill
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
//--------------------------------------------------
|
||||
// Sizes are from InVision design specs.
|
||||
open var topTypographicalStyleSpacingConfig: TypographicalStyleSpacingConfig = {
|
||||
let configs = [
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleLarge, .TitleLarge],
|
||||
neighboring: [.BodySmall, .BodyMedium, .BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge],
|
||||
neighboring: [.TitleMedium, .BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.TitleMedium, .TitleLarge],
|
||||
spacing: 16.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.TitleMedium, .TitleLarge],
|
||||
spacing: 16.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge],
|
||||
neighboring: [.BodyLarge, .BodyMedium, .BodySmall, .TitleMedium],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.BodyLarge, .BodyMedium, .TitleMedium],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall],
|
||||
neighboring: [.TitleLarge, .BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.TitleLarge, .TitleXLarge],
|
||||
spacing: 16.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPhone)
|
||||
]
|
||||
return TypographicalStyleSpacingConfig(configs: configs)
|
||||
}()
|
||||
|
||||
open var bottomTypographicalStyleSpacingConfig: TypographicalStyleSpacingConfig = {
|
||||
let configs = [
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleLarge, .TitleLarge],
|
||||
neighboring: [.BodySmall, .BodyMedium, .BodyLarge],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge],
|
||||
neighboring: [.TitleMedium, .BodyLarge],
|
||||
spacing: 16.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.TitleMedium, .TitleLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.TitleMedium, .TitleLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPad),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge],
|
||||
neighboring: [.BodyLarge, .BodyMedium, .BodySmall, .TitleMedium],
|
||||
spacing: 12.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall],
|
||||
neighboring: [.BodyLarge, .BodyMedium, .TitleMedium],
|
||||
spacing: 16,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall],
|
||||
neighboring: [.TitleLarge, .BodyLarge],
|
||||
spacing: 16.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.TitleLarge, .TitleXLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPhone),
|
||||
|
||||
TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium],
|
||||
neighboring: [.BodyLarge],
|
||||
spacing: 24.0,
|
||||
deviceType: .iPhone)
|
||||
]
|
||||
return TypographicalStyleSpacingConfig(configs: configs)
|
||||
}()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var textPosition: TitleLockupTextPosition = .left { didSet { didChange() }}
|
||||
|
||||
//style
|
||||
open var titleTypograpicalStyle: TitleLockupTitleTypographicalStyle = .BoldFeatureXSmall { didSet { didChange() }}
|
||||
open var otherTypograpicalStyle: TitleLockupOtherTypographicalStyle = UIDevice.isIPad ? .BodyLarge : .BodyMedium { didSet { didChange() }}
|
||||
|
||||
//first row
|
||||
open var eyebrowLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
}
|
||||
open var eyebrowText: String = "" { didSet { didChange() }}
|
||||
open var eyebrowTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
//second row
|
||||
open var titleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
}
|
||||
open var titleText: String = "" { didSet { didChange() }}
|
||||
open var titleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
//third row
|
||||
open var subTitleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
}
|
||||
open var subTitleText: String = "" { didSet { didChange() }}
|
||||
open var subTitleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
open var subTitleColor: Use = .primary { didSet { didChange() }}
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
isAccessibilityElement = true
|
||||
accessibilityTraits = .button
|
||||
addSubview(stackView)
|
||||
|
||||
stackView.spacing = 0.0
|
||||
|
||||
stackView.addArrangedSubview(eyebrowLabel)
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
stackView.addArrangedSubview(subTitleLabel)
|
||||
|
||||
//pin stackview to edges
|
||||
stackView.pinToSuperView()
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
titleLabel.reset()
|
||||
eyebrowLabel.reset()
|
||||
subTitleLabel.reset()
|
||||
|
||||
textPosition = .left
|
||||
|
||||
eyebrowText = ""
|
||||
eyebrowTextAttributes = nil
|
||||
titleText = ""
|
||||
titleTextAttributes = nil
|
||||
subTitleText = ""
|
||||
subTitleTextAttributes = nil
|
||||
titleTextAttributes = nil
|
||||
titleTypograpicalStyle = .BoldFeatureXSmall
|
||||
otherTypograpicalStyle = .BodyLarge
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - State
|
||||
//--------------------------------------------------
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
let allLabelsTextPosition = textPosition.labelTextPosition
|
||||
|
||||
eyebrowLabel.textPosition = allLabelsTextPosition
|
||||
eyebrowLabel.typograpicalStyle = otherTypograpicalStyle.value
|
||||
eyebrowLabel.text = eyebrowText
|
||||
eyebrowLabel.attributes = eyebrowTextAttributes
|
||||
eyebrowLabel.surface = surface
|
||||
|
||||
titleLabel.textPosition = allLabelsTextPosition
|
||||
titleLabel.typograpicalStyle = titleTypograpicalStyle.value
|
||||
titleLabel.text = titleText
|
||||
titleLabel.attributes = titleTextAttributes
|
||||
titleLabel.surface = surface
|
||||
|
||||
subTitleLabel.textPosition = allLabelsTextPosition
|
||||
subTitleLabel.typograpicalStyle = otherTypograpicalStyle.value
|
||||
subTitleLabel.text = subTitleText
|
||||
subTitleLabel.attributes = subTitleTextAttributes
|
||||
subTitleLabel.surface = surface
|
||||
subTitleLabel.disabled = subTitleColor == .secondary
|
||||
|
||||
//if both first 2 rows not empty set spacing
|
||||
if !eyebrowText.isEmpty && !titleText.isEmpty {
|
||||
stackView.spacing = getTopSpacing()
|
||||
} else {
|
||||
stackView.spacing = 0.0
|
||||
}
|
||||
|
||||
//if either first 2 rows not empty and subtile not empty, create space else collapse
|
||||
if (!eyebrowText.isEmpty || !titleText.isEmpty) && !subTitleText.isEmpty {
|
||||
stackView.setCustomSpacing(getBottomSpacing(), after: titleLabel)
|
||||
} else if (!eyebrowText.isEmpty || !titleText.isEmpty) && subTitleText.isEmpty {
|
||||
stackView.setCustomSpacing(0.0, after: titleLabel)
|
||||
}
|
||||
}
|
||||
|
||||
open func getTopSpacing() -> CGFloat {
|
||||
topTypographicalStyleSpacingConfig.spacing(for: titleTypograpicalStyle.value, neighboring: otherTypograpicalStyle.value)
|
||||
}
|
||||
|
||||
open func getBottomSpacing() -> CGFloat {
|
||||
bottomTypographicalStyleSpacingConfig.spacing(for: titleTypograpicalStyle.value, neighboring: otherTypograpicalStyle.value)
|
||||
}
|
||||
}
|
||||
|
||||
extension TypographicalStyle {
|
||||
func isWithin(_ collection: [TypographicalStyle]) -> Bool {
|
||||
(collection.first(where: {$0 == self}) != nil)
|
||||
}
|
||||
}
|
||||
|
||||
15
VDS/Extensions/VDSColor.swift
Normal file
15
VDS/Extensions/VDSColor.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// VDSColor.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 12/16/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
import UIKit
|
||||
|
||||
extension VDSColor {
|
||||
public static let elementsLowContrastOnLight = UIColor.init(hexString: "#D8DADA")
|
||||
public static let elementsLowContrastOnDark = UIColor.init(hexString: "#333333")
|
||||
}
|
||||
19
VDS/Protocols/EnumSubset.swift
Normal file
19
VDS/Protocols/EnumSubset.swift
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// EnumSubset.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 12/19/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol EnumSubset<T>: RawRepresentable, CaseIterable {
|
||||
associatedtype T:RawRepresentable
|
||||
var defaultValue: T { get }
|
||||
}
|
||||
|
||||
extension EnumSubset where RawValue == T.RawValue {
|
||||
public var value: T {
|
||||
T(rawValue: rawValue) ?? defaultValue
|
||||
}
|
||||
}
|
||||
@ -281,3 +281,36 @@ extension TypographicalStyle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct TypographicalStyleSpacingConfig {
|
||||
public var defaultSpacing: CGFloat = 8.0
|
||||
public var configs: [TypographicalStyleDeviceSpacingConfig]
|
||||
|
||||
public func spacing(for style: TypographicalStyle, neighboring: TypographicalStyle) -> CGFloat {
|
||||
let deviceType: TypographicalStyleDeviceSpacingConfig.DeviceType = UIDevice.isIPad ? .iPad : .iPhone
|
||||
if let config = configs.first(where:
|
||||
{ style.isWithin($0.primaryStyles) && neighboring.isWithin($0.neighboringStyles) &&
|
||||
($0.deviceType == deviceType || $0.deviceType == .all )})
|
||||
{
|
||||
return config.spacing
|
||||
}
|
||||
return defaultSpacing
|
||||
}
|
||||
}
|
||||
|
||||
public struct TypographicalStyleDeviceSpacingConfig {
|
||||
public enum DeviceType {
|
||||
case iPhone, iPad, all
|
||||
}
|
||||
public var spacing: CGFloat
|
||||
public var deviceType: DeviceType = .iPhone
|
||||
public var primaryStyles: [TypographicalStyle]
|
||||
public var neighboringStyles: [TypographicalStyle]
|
||||
|
||||
public init(_ primaryStyles: [TypographicalStyle], neighboring: [TypographicalStyle], spacing: CGFloat, deviceType: DeviceType = .iPhone) {
|
||||
self.spacing = spacing
|
||||
self.primaryStyles = primaryStyles
|
||||
self.neighboringStyles = neighboring
|
||||
self.deviceType = deviceType
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user