Merge branch 'build' into 'develop'

release version back into develop

See merge request BPHV_MIPS/vds_ios!94
This commit is contained in:
Bruce, Matt R 2023-07-22 17:22:58 +00:00
commit a034648c01
15 changed files with 630 additions and 413 deletions

View File

@ -13,6 +13,13 @@
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; };
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C362A681CCE00E5C127 /* ToggleView.swift */; };
EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */; };
EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */; };
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */; };
EA0D1C3F2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C3E2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift */; };
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */; };
EA0D1C432A6AD70900E5C127 /* VDSTypography.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C422A6AD70900E5C127 /* VDSTypography.swift */; };
EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */; };
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; };
EA1DA1CB2A2E36DC001C51D2 /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1DA1CA2A2E36DC001C51D2 /* SelectorBase.swift */; };
EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1F266128B945070033E859 /* RadioSwatch.swift */; };
@ -150,6 +157,13 @@
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
EA0D1C362A681CCE00E5C127 /* ToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleView.swift; sourceTree = "<group>"; };
EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+SpacingConfig.swift"; sourceTree = "<group>"; };
EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typogprahy+Styles.swift"; sourceTree = "<group>"; };
EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+Enums.swift"; sourceTree = "<group>"; };
EA0D1C3E2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+ContentSizeCategory.swift"; sourceTree = "<group>"; };
EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+Additional.swift"; sourceTree = "<group>"; };
EA0D1C422A6AD70900E5C127 /* VDSTypography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSTypography.swift; sourceTree = "<group>"; };
EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
EA1DA1CA2A2E36DC001C51D2 /* SelectorBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = "<group>"; };
EA1F266128B945070033E859 /* RadioSwatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = "<group>"; };
@ -446,6 +460,7 @@
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
EABFEB632A26473700C4C106 /* NSAttributedString.swift */,
EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */,
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
EA3361A7288B23300071C351 /* UIColor.swift */,
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
@ -455,6 +470,7 @@
EAD062A62A3B67770015965D /* UIView+CALayer.swift */,
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
EA985C662970C21600F2FF2E /* VDSLayout.swift */,
EA0D1C422A6AD70900E5C127 /* VDSTypography.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -638,6 +654,11 @@
isa = PBXGroup;
children = (
EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */,
EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */,
EA0D1C3E2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift */,
EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */,
EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */,
EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */,
);
path = Typography;
sourceTree = "<group>";
@ -881,7 +902,9 @@
EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */,
EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */,
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */,
EA0D1C3F2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift in Sources */,
EA5F86C82A1BD99100BC83E4 /* TabModel.swift in Sources */,
EA0D1C432A6AD70900E5C127 /* VDSTypography.swift in Sources */,
EA297A5729FB0A360031ED56 /* AppleGuidlinesTouchable.swift in Sources */,
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */,
@ -891,6 +914,7 @@
EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */,
EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */,
EAB2375D29E8789100AABE9A /* Tooltip.swift in Sources */,
EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */,
EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */,
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
@ -900,6 +924,7 @@
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */,
EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */,
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */,
EAC925842911C63100091998 /* Colorable.swift in Sources */,
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,
EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */,
@ -935,7 +960,9 @@
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */,
EA0D1C3B2A6AD51B00E5C127 /* Typogprahy+Styles.swift in Sources */,
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */,
EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */,
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */,
@ -966,6 +993,7 @@
EA3361B6288B2A410071C351 /* Control.swift in Sources */,
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */,
EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */,
EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */,
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
@ -1135,7 +1163,7 @@
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 28;
CURRENT_PROJECT_VERSION = 33;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
@ -1172,7 +1200,7 @@
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 28;
CURRENT_PROJECT_VERSION = 33;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;

View File

@ -53,6 +53,8 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
open var attributes: [any LabelAttributeModel]? { nil }
open var useScaledFont: Bool = false { didSet { setNeedsUpdate() }}
open var surface: Surface = .light { didSet { setNeedsUpdate() }}
open var userInfo = [String: Primitive]()
@ -177,6 +179,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: text ?? "No Text",
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColor,
alignment: titleLabel?.textAlignment ?? .center,
lineBreakMode: titleLabel?.lineBreakMode ?? .byTruncatingTail)

View File

@ -27,6 +27,8 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
open var useAttributedText: Bool = false
open var useScaledFont: Bool = false { didSet { setNeedsUpdate() }}
open var surface: Surface = .light { didSet { setNeedsUpdate() }}
open var attributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }}
@ -89,6 +91,13 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
//--------------------------------------------------
open func initialSetup() {
if !initialSetupPerformed {
//register for ContentSizeChanges
NotificationCenter
.Publisher(center: .default, name: UIContentSizeCategory.didChangeNotification)
.sink { [weak self] notification in
self?.setNeedsUpdate()
}.store(in: &subscribers)
backgroundColor = .clear
numberOfLines = 0
lineBreakMode = .byWordWrapping
@ -135,6 +144,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: text,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColorConfiguration.getColor(self),
alignment: textPosition.textAlignment,
lineBreakMode: lineBreakMode)

View File

@ -19,20 +19,39 @@ extension NSAttributedString {
}
extension NSMutableAttributedString {
public static func mutableText(for text: String, textStyle: TextStyle, textColor: UIColor, alignment: NSTextAlignment = .left, lineBreakMode: NSLineBreakMode) -> NSMutableAttributedString {
public static var useMinimumLineHeight: Bool = true
public static var useScaledLineHeight: Bool = false
public static func mutableText(for text: String, textStyle: TextStyle, useScaledFont: Bool = true, textColor: UIColor, alignment: NSTextAlignment = .left, lineBreakMode: NSLineBreakMode) -> NSMutableAttributedString {
//var for if you can scale or not
let scaledMode = useScaledFont && TextStyle.canScaleFonts
//create the paragraph for specific properties
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = alignment
paragraph.lineBreakMode = lineBreakMode
var defaultFont = textStyle.font
var lineHeight = textStyle.lineHeight
if scaledMode {
defaultFont = defaultFont.scaledFont
if useScaledLineHeight {
lineHeight = textStyle.scaledLineHeight
}
}
//set lineHeight
if textStyle.lineHeight > 0.0 {
paragraph.maximumLineHeight = textStyle.lineHeight
if useMinimumLineHeight {
paragraph.minimumLineHeight = lineHeight
}
paragraph.maximumLineHeight = lineHeight
}
//create the attributeArray
var attributes: [NSAttributedString.Key : Any] = [.font: textStyle.font,
var attributes: [NSAttributedString.Key : Any] = [.font: defaultFont,
.foregroundColor: textColor,
.paragraphStyle: paragraph]

View File

@ -0,0 +1,15 @@
//
// RawRepresentable.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
/// Helper method to check to see if you exist in a collection
extension RawRepresentable where Self.RawValue: Equatable {
public func isWithin(_ collection: [Self]) -> Bool {
(collection.first(where: {$0 == self}) != nil)
}
}

View File

@ -0,0 +1,14 @@
//
// VDSTypography.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import VDSTypographyTokens
extension VDSTypography {
public static let letterSpacingSemiWide: CGFloat = 0.25
}

View File

@ -39,13 +39,16 @@ extension FontProtocol {
throw error!.takeUnretainedValue()
}
}
public func font(ofSize size: CGFloat) -> UIFont{
public func font(ofSize size: CGFloat, isScaled: Bool = true) -> UIFont{
DispatchQueue.once(block: { self.register() })
if let font = UIFont(name: self.fontName, size: size){
return UIFontMetrics.default.scaledFont(for: font)
} else {
return UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: size))
}
guard let found = UIFont(name: self.fontName, size: size) else { return .systemFont(ofSize: size) }
return found
}
}
extension UIFont {
public var scaledFont: UIFont {
UIFontMetrics.default.scaledFont(for: self)
}
}

View File

@ -15,4 +15,13 @@ extension UITextField {
.map { _ in self.text ?? "" }
.eraseToAnyPublisher()
}
public var numberPublisher: AnyPublisher<NSNumber?, Never> {
publisher(for: .editingChanged)
.map { textField in
guard let text = textField.text, let foundNumber = NumberFormatter().number(from: text) else { return nil }
return foundNumber
}
.eraseToAnyPublisher()
}
}

View File

@ -1,3 +1,26 @@
1.0.33
=======
- Add test variable to use ratio line height or not
1.0.32
=======
- Fixed bug dealing with Scaled
- Added ability to use minimumLineheight in Paragraph for AttributedString creation
1.0.31
=======
- updated version only
1.0.30
=======
- Updated Label to allow Scaled Fonts
- Refactored Code TextStyle
1.0.29
=======
- Updated TextStyle and Label for dealing with Top/Bottom insets
- Refactored Code for Checkbox/RadioButton/Toggle
1.0.28
=======
- CXTDT-423141- Tabs - Incorrect spacing on top-aligned Fill container

View File

@ -0,0 +1,251 @@
//
// Typogprahy+Styles.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import VDSTypographyTokens
//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: VDSTypography.letterSpacingSemiWide)
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)
public static let featureLarge = TextStyle(rawValue: "featureLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureMedium = TextStyle(rawValue: "featureMedium",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureSmall = TextStyle(rawValue: "featureSmall",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureXSmall = TextStyle(rawValue: "featureXSmall",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let title2XLarge = TextStyle(rawValue: "title2XLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let titleXLarge = TextStyle(rawValue: "titleXLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let titleLarge = TextStyle(rawValue: "titleLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
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)
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)
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)
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)
public static let bodyLarge = TextStyle(rawValue: "bodyLarge",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing:VDSTypography.letterSpacingWide)
public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodyMedium = TextStyle(rawValue: "bodyMedium",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodySmall = TextStyle(rawValue: "bodySmall",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16,
letterSpacing: 0)
public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16,
letterSpacing: 0)
public static let micro = TextStyle(rawValue: "micro",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16,
letterSpacing: 0)
public static let boldMicro = TextStyle(rawValue: "boldMicro",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16,
letterSpacing: 0)
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
]
}
}
extension TextStyle {
public enum StandardStyle: String, CaseIterable {
case featureXLarge,
featureLarge,
featureMedium,
featureSmall,
featureXSmall,
title2XLarge,
titleXLarge,
titleLarge,
titleMedium,
titleSmall,
bodyLarge,
bodyMedium,
bodySmall,
micro
public var bold: TextStyle {
return TextStyle(rawValue: "bold\(rawValue.prefix(1).uppercased())\(rawValue.dropFirst())")!
}
public var regular: TextStyle {
TextStyle(rawValue: rawValue)!
}
}
public func toStandardStyle() -> StandardStyle {
var rawName = rawValue
if rawName.hasPrefix("bold") {
let updatedRaw = rawName.replacingOccurrences(of: "bold", with: "")
rawName = updatedRaw.prefix(1).lowercased() + updatedRaw.dropFirst()
}
return StandardStyle(rawValue: rawName)!
}
}

View File

@ -0,0 +1,76 @@
//
// Typography+Additional.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import UIKit
import VDSTypographyTokens
//MARK: Alignments
extension TextStyle {
/// Alignments Available for the TextStyle
public var aligments: [TextPosition] {
return [.left, .center]
}
}
//MARK: Fonts
extension TextStyle {
/// Font for the TextStyle.
public var font: UIFont {
return fontFace.font(ofSize: pointSize)
}
}
//MARK: Style Helper
extension TextStyle {
/// Default style used if no style is given.
public static var defaultStyle: TextStyle { return bodyLarge }
/// Find a TextStyle based off a Name.
/// - Parameter name: Name of the TextStyle you want to find.
/// - Returns: TextStyle for the given name.
public static func textStyle(for name: String) -> TextStyle? {
guard let style = TextStyle.allCases.first(where: {$0.rawValue == name }) else { return nil }
return style
}
/// Returns a TextStyle based off a Font-Name and Size
/// - Parameters:
/// - fontName: Name of the font you want to find.
/// - size: PointSize of the Font you want to find.
/// - Returns: The exact TextStyle based on the FontName and Point Size.
public static func style(for fontName: String, size: CGFloat) -> TextStyle? {
//filter all styles by fontName
let styles = allCases.filter{$0.fontFace.fontName == fontName }.sorted { lhs, rhs in lhs.pointSize < rhs.pointSize }
//if there are no styles then return nil
guard styles.count > 0 else { return nil }
//if there is an exact match on a style with this pointSize then return it
if let style = styles.first(where: {$0.pointSize == size }) {
return style
} else if let largerIndex = styles.firstIndex(where: { $0.pointSize > size}) { //find the closet one to pointSize
return styles[max(largerIndex - 1, 0)]
} else { //return the last style
return styles.last!
}
}
}
extension TextStyle: CustomDebugStringConvertible {
/// Used for showing the TextStyle Properties.
public var debugDescription: String {
"Name: \(self.rawValue) FontFace: \(font.fontName) FontWeight: \(self.rawValue.hasPrefix("bold") ? "bold" : "normal") PointSize: \(font.pointSize) LetterSpacing: \(letterSpacing) LineHeight: \(lineHeight)"
}
}

View File

@ -0,0 +1,30 @@
//
// Typography+ContentSizeCategory.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import UIKit
extension TextStyle {
/// Determines if the Framework can use scaled fonts for preferredContentSizeCategory
public static var allowScaledFonts: Bool = true
/// Determines is the User has changed their default preferredContentSizeCategory
public static var canScaleFonts: Bool {
UIApplication.shared.preferredContentSizeCategory != .large && allowScaledFonts
}
/// The scaled version of the hardcode value 'lineHeight' within a TextStyle. This will only be different
/// from the original if the preferredContentSizeCategory has changed.
public var scaledLineHeight: CGFloat {
let defaultFont = font
let scaledFont = defaultFont.scaledFont
let ratio = scaledFont.pointSize / defaultFont.pointSize
let newLineHeight = (lineHeight * ratio).rounded()
return newLineHeight
}
}

View File

@ -0,0 +1,92 @@
//
// Typography+Enums.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import UIKit
//MARK: FontCategory
extension TextStyle {
/// Used in the Sample App but could be used elsewhere to allow selection of TextStyles
public enum FontCategory: String, CaseIterable {
case feature
case title
case body
case micro
public var sizes: [FontSize] {
switch self {
case .feature:
return [.xlarge, .large, .medium, .small, .xsmall]
case .title:
return [.xxlarge, .xlarge, .large, .medium, .small]
case .body:
return [.large, .medium, .small]
case .micro:
return []
}
}
/// Find the TextStyle for the FontSize.
/// - Parameters:
/// - fontSize: FontSize you are looking for using this FontCategory.
/// - isBold: Whether or not the Font is bold.
/// - Returns: A TextStyle will be returned if all criteria is met, otherwise nil will be returned.
public func style(for fontSize: FontSize?, isBold: Bool = false) -> TextStyle? {
var styleName = ""
if isBold {
let newRaw = rawValue.prefix(1).description.uppercased() + rawValue.dropFirst()
styleName = "\(isBold ? "bold" : "")\(newRaw)\(fontSize?.rawValue ?? "")"
} else {
styleName = "\(rawValue)\(fontSize?.rawValue ?? "")"
}
guard let style = TextStyle.textStyle(for: styleName) else {
return nil
}
return style
}
}
/// Find the TextStyle for the specific FontCategory and FontSize.
/// - Parameters:
/// - category: FontCategory you are looking for in the TextStyle
/// - fontSize: FontSize you are looking for using the given FontCategory.
/// - isBold: Whether or not the Font is bold.
/// - Returns: A TextStyle will be returned if all criteria is met, otherwise nil will be returned.
public func style(for category: FontCategory, with size: FontSize, isBold: Bool) -> TextStyle? {
category.style(for: size, isBold: isBold)
}
}
//MARK: FontSize
extension TextStyle {
public enum FontSize: String, CaseIterable {
case xxlarge = "2XLarge"
case xlarge = "XLarge"
case large = "Large"
case medium = "Medium"
case small = "Small"
case xsmall = "XSmall"
}
}
public enum TextPosition: String, CaseIterable {
case left, right, center
var textAlignment: NSTextAlignment {
switch self {
case .left:
return NSTextAlignment.left
case .right:
return NSTextAlignment.right
case .center:
return NSTextAlignment.center
}
}
}

View File

@ -0,0 +1,44 @@
//
// Typography+Spacing.swift
// VDS
//
// Created by Matt Bruce on 7/21/23.
//
import Foundation
import UIKit
extension TextStyle {
public struct SpacingConfig {
public var defaultSpacing: CGFloat = 8.0
public var configs: [TextStyle.DeviceSpacingConfig]
public func spacing(for style: TextStyle, neighboring: TextStyle) -> CGFloat {
let deviceType: TextStyle.DeviceSpacingConfig.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 DeviceSpacingConfig {
public enum DeviceType {
case iPhone, iPad, all
}
public var spacing: CGFloat
public var deviceType: DeviceType = .iPhone
public var primaryStyles: [TextStyle]
public var neighboringStyles: [TextStyle]
public init(_ primaryStyles: [TextStyle], neighboring: [TextStyle], spacing: CGFloat, deviceType: DeviceType = .iPhone) {
self.spacing = spacing
self.primaryStyles = primaryStyles
self.neighboringStyles = neighboring
self.deviceType = deviceType
}
}
}

View File

@ -8,21 +8,8 @@
import Foundation
import VDSTypographyTokens
public enum TextPosition: String, CaseIterable {
case left, right, center
var textAlignment: NSTextAlignment {
switch self {
case .left:
return NSTextAlignment.left
case .right:
return NSTextAlignment.right
case .center:
return NSTextAlignment.center
}
}
}
/// This is the Definition that will determine how the Text is drawn
public struct TextStyle: Equatable, RawRepresentable {
public let rawValue: String
public let pointSize: CGFloat
@ -54,390 +41,3 @@ public struct TextStyle: Equatable, RawRepresentable {
rawValue.hasPrefix("bold")
}
}
extension VDSTypography {
public static let letterSpacingSemiWide: CGFloat = 0.25
}
//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: VDSTypography.letterSpacingSemiWide)
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)
public static let featureLarge = TextStyle(rawValue: "featureLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureMedium = TextStyle(rawValue: "featureMedium",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureSmall = TextStyle(rawValue: "featureSmall",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let featureXSmall = TextStyle(rawValue: "featureXSmall",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let title2XLarge = TextStyle(rawValue: "title2XLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let titleXLarge = TextStyle(rawValue: "titleXLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
public static let titleLarge = TextStyle(rawValue: "titleLarge",
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
letterSpacing: VDSTypography.letterSpacingSemiWide)
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)
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)
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)
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)
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)
public static let bodyLarge = TextStyle(rawValue: "bodyLarge",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing:VDSTypography.letterSpacingWide)
public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodyMedium = TextStyle(rawValue: "bodyMedium",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodySmall = TextStyle(rawValue: "bodySmall",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16,
letterSpacing: 0)
public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16,
letterSpacing: 0)
public static let micro = TextStyle(rawValue: "micro",
fontFace: .dsRegular,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16,
letterSpacing: 0)
public static let boldMicro = TextStyle(rawValue: "boldMicro",
fontFace: .dsBold,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16,
letterSpacing: 0)
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
]
}
}
extension TextStyle {
public enum StandardStyle: String, CaseIterable {
case featureXLarge,
featureLarge,
featureMedium,
featureSmall,
featureXSmall,
title2XLarge,
titleXLarge,
titleLarge,
titleMedium,
titleSmall,
bodyLarge,
bodyMedium,
bodySmall,
micro
public var bold: TextStyle {
return TextStyle(rawValue: "bold\(rawValue.prefix(1).uppercased())\(rawValue.dropFirst())")!
}
public var regular: TextStyle {
TextStyle(rawValue: rawValue)!
}
}
public func toStandardStyle() -> StandardStyle {
var rawName = rawValue
if rawName.hasPrefix("bold") {
let updatedRaw = rawName.replacingOccurrences(of: "bold", with: "")
rawName = updatedRaw.prefix(1).lowercased() + updatedRaw.dropFirst()
}
return StandardStyle(rawValue: rawName)!
}
}
//MARK: FontCategory
extension TextStyle {
public enum FontCategory: String, CaseIterable {
case feature
case title
case body
case micro
public var sizes: [FontSize] {
switch self {
case .feature:
return [.xlarge, .large, .medium, .small, .xsmall]
case .title:
return [.xxlarge, .xlarge, .large, .medium, .small]
case .body:
return [.large, .medium, .small]
case .micro:
return []
}
}
public func style(for fontSize: FontSize?, isBold: Bool = false) -> TextStyle? {
var styleName = ""
if isBold {
let newRaw = rawValue.prefix(1).description.uppercased() + rawValue.dropFirst()
styleName = "\(isBold ? "bold" : "")\(newRaw)\(fontSize?.rawValue ?? "")"
} else {
styleName = "\(rawValue)\(fontSize?.rawValue ?? "")"
}
guard let style = TextStyle.textStyle(for: styleName) else {
return nil
}
return style
}
}
}
//MARK: FontSize
extension TextStyle {
public enum FontSize: String, CaseIterable {
case xxlarge = "2XLarge"
case xlarge = "XLarge"
case large = "Large"
case medium = "Medium"
case small = "Small"
case xsmall = "XSmall"
}
}
//MARK: Alignments
extension TextStyle {
public var aligments: [TextPosition] {
return [.left, .center]
}
}
//MARK: Fonts
extension TextStyle {
public var font: UIFont {
return fontFace.font(ofSize: pointSize)
}
}
extension TextStyle {
public static func style(for fontName: String, size: CGFloat) -> TextStyle? {
//filter all styles by fontName
let styles = allCases.filter{$0.fontFace.fontName == fontName }.sorted { lhs, rhs in lhs.pointSize < rhs.pointSize }
//if there are no styles then return nil
guard styles.count > 0 else { return nil }
//if there is an exact match on a style with this pointSize then return it
if let style = styles.first(where: {$0.pointSize == size }) {
return style
} else if let largerIndex = styles.firstIndex(where: { $0.pointSize > size}) { //find the closet one to pointSize
return styles[max(largerIndex - 1, 0)]
} else { //return the last style
return styles.last!
}
}
}
extension RawRepresentable where Self.RawValue: Equatable {
public func isWithin(_ collection: [Self]) -> Bool {
(collection.first(where: {$0 == self}) != nil)
}
}
extension TextStyle {
public struct SpacingConfig {
public var defaultSpacing: CGFloat = 8.0
public var configs: [TextStyle.DeviceSpacingConfig]
public func spacing(for style: TextStyle, neighboring: TextStyle) -> CGFloat {
let deviceType: TextStyle.DeviceSpacingConfig.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 DeviceSpacingConfig {
public enum DeviceType {
case iPhone, iPad, all
}
public var spacing: CGFloat
public var deviceType: DeviceType = .iPhone
public var primaryStyles: [TextStyle]
public var neighboringStyles: [TextStyle]
public init(_ primaryStyles: [TextStyle], neighboring: [TextStyle], spacing: CGFloat, deviceType: DeviceType = .iPhone) {
self.spacing = spacing
self.primaryStyles = primaryStyles
self.neighboringStyles = neighboring
self.deviceType = deviceType
}
}
}
extension TextStyle: CustomDebugStringConvertible {
public var debugDescription: String {
"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
}
}