Merge branch 'vasavk/modal' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into mbruce/modal

This commit is contained in:
Matt Bruce 2024-10-03 09:19:29 -05:00
commit 0aab83c4cb
16 changed files with 430 additions and 271 deletions

View File

@ -69,6 +69,8 @@
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C402A6AD61C00E5C127 /* Typography+Additional.swift */; };
EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0D1C442A6AD73000E5C127 /* RawRepresentable.swift */; };
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; };
EA225FC72CA4845100B6B3B3 /* LanguageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */; };
EA225FC92CA4932900B6B3B3 /* Typography+StyleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */; };
EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; };
EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */; };
EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; };
@ -270,7 +272,7 @@
44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TableChangeLog.txt; sourceTree = "<group>"; };
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>"; };
710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = "<group>"; };
710607942B91A99500F2863F /* TileletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileletChangeLog.txt; sourceTree = "<group>"; };
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = "<group>"; };
71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = "<group>"; };
@ -298,6 +300,8 @@
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>"; };
EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = "<group>"; };
EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageManager.swift; sourceTree = "<group>"; };
EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Typography+StyleProvider.swift"; sourceTree = "<group>"; };
EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = "<group>"; };
EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesTouchable.swift; sourceTree = "<group>"; };
EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = "<group>"; };
@ -840,12 +844,13 @@
EA3361B4288B2A360071C351 /* Classes */ = {
isa = PBXGroup;
children = (
EAF2F4752C231EAA007BFEDC /* AccessibilityActionElement.swift */,
EAF2F4882C2A1075007BFEDC /* AlertViewController.swift */,
EA985C1C296CD13600F2FF2E /* BundleManager.swift */,
EAC58C282BF4118C00BA39FA /* ClearPopoverViewController.swift */,
EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */,
EA225FC62CA4845100B6B3B3 /* LanguageManager.swift */,
EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */,
EAF2F4752C231EAA007BFEDC /* AccessibilityActionElement.swift */,
EAF2F4882C2A1075007BFEDC /* AlertViewController.swift */,
);
path = Classes;
sourceTree = "<group>";
@ -958,7 +963,7 @@
EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */,
EA985BE929689B6D00F2FF2E /* TileletSubTitleModel.swift */,
EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */,
710607942B91A99500F2863F /* TitleletChangeLog.txt */,
710607942B91A99500F2863F /* TileletChangeLog.txt */,
);
path = Tilelet;
sourceTree = "<group>";
@ -1013,6 +1018,7 @@
EA0D1C3C2A6AD57600E5C127 /* Typography+Enums.swift */,
EA0D1C382A6AD4DF00E5C127 /* Typography+SpacingConfig.swift */,
EA0D1C3A2A6AD51B00E5C127 /* Typogprahy+Styles.swift */,
EA225FC82CA4932900B6B3B3 /* Typography+StyleProvider.swift */,
);
path = Typography;
sourceTree = "<group>";
@ -1399,6 +1405,7 @@
44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */,
71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */,
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
EA225FC72CA4845100B6B3B3 /* LanguageManager.swift in Sources */,
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
@ -1436,6 +1443,7 @@
44604AD729CE196600E62B51 /* Line.swift in Sources */,
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */,
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
EA225FC92CA4932900B6B3B3 /* Typography+StyleProvider.swift in Sources */,
EAC58C062BED000200BA39FA /* CreditCard.swift in Sources */,
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */,

View File

@ -0,0 +1,63 @@
//
// LanguageManager.swift
// VDS
//
// Created by Matt Bruce on 9/25/24.
//
import Foundation
// Language Manager to control the current language setting
public class LanguageManager {
// Enum to define supported languages
public enum SupportedLanguage: String, CustomStringConvertible {
case english = "en"
case spanish = "es"
public var description: String { self == .english ? "English" : "Spanish"}
}
// Private static variable to hold the in-memory current language
private static var _currentLanguage: SupportedLanguage? {
didSet {
TextStyle.Provider.updateCurrentStyles()
}
}
// Static property to manage the current language setting
public static var currentLanguage: SupportedLanguage {
get {
// Check if there is an in-memory language setting
guard let _currentLanguage else {
// set default
var deviceCurrentLanguage: SupportedLanguage = .english
// Check device's preferred language
let deviceLanguage = Locale.preferredLanguages.first ?? "en"
if deviceLanguage.starts(with: "es") {
deviceCurrentLanguage = .spanish
}
_currentLanguage = deviceCurrentLanguage
return deviceCurrentLanguage
}
return _currentLanguage
}
set {
// Set the in-memory language
_currentLanguage = newValue
}
}
// Method to set language using a language code string
public static func setLanguage(with code: String) {
if code.starts(with: "es") {
_currentLanguage = .spanish
} else {
_currentLanguage = .english
}
}
}

View File

@ -183,6 +183,15 @@ open class DatePicker: EntryFieldBase<String> {
showPopover()
}
}
containerView.accessibilityTraits = [.button]
containerView.bridge_accessibilityHintBlock = { [weak self] in
guard let self else { return "" }
return isReadOnly || !isEnabled
? ""
: isCalendarShowing ? "Expanded, Double tap to close" : "Collapsed, \(accessibilityHintText)"
}
}
open override func getFieldContainer() -> UIView {

View File

@ -61,8 +61,9 @@ open class DropdownSelect: EntryFieldBase<String> {
internal var minWidthInlineLabel = 102.0
internal override var minWidth: CGFloat { showInlineLabel ? minWidthInlineLabel : minWidthDefault }
internal override var maxWidth: CGFloat {
let frameWidth = frame.size.width
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth
let frameWidth = constrainedWidth
let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
return helperTextPlacement == .right && halfWidth > minWidth * 2 ? halfWidth : frameWidth
}
/// The is used for the for adding the helperLabel to the right of the containerView.

View File

@ -83,7 +83,7 @@ open class FootnoteGroup: View {
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
internal var maxWidth: CGFloat { horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width) }
internal var maxWidth: CGFloat { constrainedWidth }
internal var minWidth: CGFloat { containerSize.width }
internal var containerSize: CGSize { CGSize(width: 55, height: 44) }

View File

@ -152,7 +152,7 @@ open class FootnoteItem: View {
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
internal var maxWidth: CGFloat { horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width) }
internal var maxWidth: CGFloat { constrainedWidth }
internal var minWidth: CGFloat { containerSize.width }
internal var containerSize: CGSize { CGSize(width: 45, height: 44) }

View File

@ -331,9 +331,7 @@ open class InputStepper: EntryFieldBase<Int> {
stepperWidthConstraint?.deactivate()
widthConstraint?.deactivate()
trailingLessThanEqualsConstraint?.deactivate()
trailingEqualsConstraint?.deactivate()
var widthConstraintConstant: CGFloat?
if let widthPercentage, let superWidth = horizontalPinnedWidth() {
@ -350,9 +348,6 @@ open class InputStepper: EntryFieldBase<Int> {
if let widthConstraintConstant {
widthConstraint?.constant = widthConstraintConstant
widthConstraint?.activate()
trailingLessThanEqualsConstraint?.activate()
} else {
trailingEqualsConstraint?.activate()
}
// Update Edge insets if size changes applied.

View File

@ -105,14 +105,12 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
// MARK: - Constraints
//--------------------------------------------------
internal var widthConstraint: NSLayoutConstraint?
internal var trailingEqualsConstraint: NSLayoutConstraint?
internal var trailingLessThanEqualsConstraint: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
// Sizes are from InVision design specs.
internal var maxWidth: CGFloat { frame.size.width }
internal var maxWidth: CGFloat { constrainedWidth }
internal var minWidth: CGFloat { containerSize.width }
internal var containerSize: CGSize { CGSize(width: minWidth, height: 44) }
@ -258,15 +256,9 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
let layoutGuide = UILayoutGuide()
addLayoutGuide(layoutGuide)
layoutGuide
.pinTop()
.pinLeading()
.pinBottom()
trailingEqualsConstraint = layoutGuide.pinTrailing(anchor: trailingAnchor)
layoutGuide.pinToSuperView()
// width constraints
trailingLessThanEqualsConstraint = layoutGuide.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate()
widthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: 0).deactivate()
// Add mainStackView to the view
@ -549,18 +541,13 @@ open class EntryFieldBase<ValueType>: Control, Changeable, FormFieldInternalVali
containerView.layer.borderWidth = VDSFormControls.borderWidth
containerView.layer.cornerRadius = VDSFormControls.borderRadius
}
internal func updateContainerWidth() {
widthConstraint?.deactivate()
trailingLessThanEqualsConstraint?.deactivate()
trailingEqualsConstraint?.deactivate()
if let width, width >= minWidth, width <= maxWidth {
widthConstraint?.constant = width
widthConstraint?.activate()
trailingLessThanEqualsConstraint?.activate()
} else {
trailingEqualsConstraint?.activate()
}
}

View File

@ -47,8 +47,9 @@ open class InputField: EntryFieldBase<String> {
internal override var minWidth: CGFloat { fieldType.handler().minWidth }
internal override var maxWidth: CGFloat {
let frameWidth = frame.size.width
return helperTextPlacement == .right ? (frameWidth - horizontalStackView.spacing) / 2 : frameWidth
let frameWidth = constrainedWidth
let halfWidth = (frameWidth - horizontalStackView.spacing) / 2
return helperTextPlacement == .right && halfWidth > minWidth * 2 ? halfWidth : frameWidth
}
/// The is used for the for adding the helperLabel to the right of the containerView.
@ -320,15 +321,12 @@ open class InputField: EntryFieldBase<String> {
internal override func updateContainerWidth() {
widthConstraint?.deactivate()
trailingLessThanEqualsConstraint?.deactivate()
trailingEqualsConstraint?.deactivate()
//see if there is a widthPercentage and follow the same pattern as done for "width"
let currentWidth = (horizontalPinnedWidth() ?? 0) * (widthPercentage ?? 0)
if currentWidth >= minWidth, currentWidth <= maxWidth {
widthConstraint?.constant = currentWidth
widthConstraint?.activate()
trailingLessThanEqualsConstraint?.activate()
} else {
super.updateContainerWidth()
}

View File

@ -447,33 +447,6 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
//-------------------------------------------------------------------------
//Overriding Nil Width Rules
//-------------------------------------------------------------------------
//Rule 1:
//In the scenario where we only have a height but the multiplie is nil, we
//want to set the width with the parent's width which will more or less "fill"
//the container horizontally
//- height is set
//- width is not set
//- aspectRatio is not set
if let superviewWidth, superviewWidth > 0,
containerViewHeight != nil,
containerViewWidth == nil,
multiplier == nil {
containerViewWidth = superviewWidth
}
//Rule 2:
//In the scenario where no width and height is set, want to set the width with the
//parent's width which will more or less "fill" the container horizontally
//- height is not set
//- width is not set
else if let superviewWidth, superviewWidth > 0,
containerViewWidth == nil,
containerViewHeight == nil {
containerViewWidth = superviewWidth
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//Width + AspectRatio Constraint
//-------------------------------------------------------------------------
@ -499,6 +472,14 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: multiplier)
aspectRatioConstraint?.activate()
}
//-------------------------------------------------------------------------
//Multiplier, meaning it was pinned with width only Constraint
//-------------------------------------------------------------------------
else if let multiplier {
aspectRatioConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: multiplier)
aspectRatioConstraint?.activate()
} else {
//-------------------------------------------------------------------------
@ -520,12 +501,6 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
}
}
}
/// This is the size of the superview's allowed space for this container first by constrained size which would include padding/inset values an
private var superviewWidth: CGFloat? {
horizontalPinnedWidth() ?? superview?.frame.size.width
}
}
extension TileContainerBase {

View File

@ -29,9 +29,9 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
public var value: CGFloat {
switch self {
case .small:
return UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space4X
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X
case .large:
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space6X
return UIDevice.isIPad ? VDSLayout.space6X : VDSLayout.space4X
}
}
@ -598,7 +598,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
}
private func updateTextPositionAlignment() {
guard width != nil && (aspectRatio != .none || height != nil) else { return }
guard aspectRatio != .none || height != nil else { return }
switch textPostion {
case .top:
titleLockupTopConstraint?.activate()

View File

@ -647,7 +647,14 @@ public enum LayoutDistribution: String, CaseIterable {
case fillProportionally
}
extension LayoutConstraintable where Self: UIView {
public var constrainedWidth: CGFloat {
horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width)
}
}
extension LayoutConstraintable {
public func removeConstraints() {
guard let view = self as? UIView, let superview = view.superview else { return }

View File

@ -1,3 +1,10 @@
1.0.74
----------------
- CXTDT-591307 - DatePicker - Accessibility - #1 & #2
- CXTDT-595956 - Tilelet - Text Position does not work on Light surface
- CXTDT-595952 - Tilelet - Aspect Ratio Width/height setting
- CXTDT-595965 - Tilelet - Incorrect Mobile Padding
1.0.73
----------------
- CXTDT-597984 - Table - Text wrap

View File

@ -11,206 +11,69 @@ import VDSCoreTokens
//MARK: Definitions
extension TextStyle {
// Static properties for different text styles
public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4))
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,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4))
public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2))
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,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2))
public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2))
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,
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2))
public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 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,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 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,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 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,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0))
public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36)
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 boldTitleLarge = TextStyle(rawValue: "boldTitleLarge",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28)
public static let titleLarge = TextStyle(rawValue: "titleLarge",
fontFace: UIDevice.isIPad ? .dsLight : .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
letterSpacing: UIDevice.isIPad ? VDSTypography.letterSpacingSemiwide : 0)
public static let boldTitleMedium = TextStyle(rawValue: "boldTitleMedium",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24)
public static let titleMedium = TextStyle(rawValue: "titleMedium",
fontFace: .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24)
public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall",
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20)
public static let titleSmall = TextStyle(rawValue: "titleSmall",
fontFace: .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20)
public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge",
fontFace: .edsBold,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodyLarge = TextStyle(rawValue: "bodyLarge",
fontFace: .edsRegular,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing:VDSTypography.letterSpacingWide)
public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium",
fontFace: .edsBold,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let bodyMedium = TextStyle(rawValue: "bodyMedium",
fontFace: .edsRegular,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide)
public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall",
fontFace: .etxBold,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16)
public static let bodySmall = TextStyle(rawValue: "bodySmall",
fontFace: .etxRegular,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16)
public static let boldMicro = TextStyle(rawValue: "boldMicro",
fontFace: .etxBold,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16)
public static let micro = TextStyle(rawValue: "micro",
fontFace: .etxRegular,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16)
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
]
internal enum Style: String, CaseIterable {
case boldFeatureXLarge
case featureXLarge
case boldFeatureLarge
case featureLarge
case boldFeatureMedium
case featureMedium
case boldFeatureSmall
case featureSmall
case boldFeatureXSmall
case featureXSmall
case boldTitle2XLarge
case title2XLarge
case boldTitleXLarge
case titleXLarge
case boldTitleLarge
case titleLarge
case boldTitleMedium
case titleMedium
case boldTitleSmall
case titleSmall
case boldBodyLarge
case bodyLarge
case boldBodyMedium
case bodyMedium
case boldBodySmall
case bodySmall
case boldMicro
case micro
}
// Static properties for different text styles
public static var boldFeatureXLarge: TextStyle { Provider.style(for: .boldFeatureXLarge) }
public static var featureXLarge: TextStyle { Provider.style(for: .featureXLarge) }
public static var boldFeatureLarge: TextStyle { Provider.style(for: .boldFeatureLarge) }
public static var featureLarge: TextStyle { Provider.style(for: .featureLarge) }
public static var boldFeatureMedium: TextStyle { Provider.style(for: .boldFeatureMedium) }
public static var featureMedium: TextStyle { Provider.style(for: .featureMedium) }
public static var boldFeatureSmall: TextStyle { Provider.style(for: .boldFeatureSmall) }
public static var featureSmall: TextStyle { Provider.style(for: .featureSmall) }
public static var boldFeatureXSmall: TextStyle { Provider.style(for: .boldFeatureXSmall) }
public static var featureXSmall: TextStyle { Provider.style(for: .featureXSmall) }
public static var boldTitle2XLarge: TextStyle { Provider.style(for: .boldTitle2XLarge) }
public static var title2XLarge: TextStyle { Provider.style(for: .title2XLarge) }
public static var boldTitleXLarge: TextStyle { Provider.style(for: .boldTitleXLarge) }
public static var titleXLarge: TextStyle { Provider.style(for: .titleXLarge) }
public static var boldTitleLarge: TextStyle { Provider.style(for: .boldTitleLarge) }
public static var titleLarge: TextStyle { Provider.style(for: .titleLarge) }
public static var boldTitleMedium: TextStyle { Provider.style(for: .boldTitleMedium) }
public static var titleMedium: TextStyle { Provider.style(for: .titleMedium) }
public static var boldTitleSmall: TextStyle { Provider.style(for: .boldTitleSmall) }
public static var titleSmall: TextStyle { Provider.style(for: .titleSmall) }
public static var boldBodyLarge: TextStyle { Provider.style(for: .boldBodyLarge) }
public static var bodyLarge: TextStyle { Provider.style(for: .bodyLarge) }
public static var boldBodyMedium: TextStyle { Provider.style(for: .boldBodyMedium) }
public static var bodyMedium: TextStyle { Provider.style(for: .bodyMedium) }
public static var boldBodySmall: TextStyle { Provider.style(for: .boldBodySmall) }
public static var bodySmall: TextStyle { Provider.style(for: .bodySmall) }
public static var boldMicro: TextStyle { Provider.style(for: .boldMicro) }
public static var micro: TextStyle { Provider.style(for: .micro) }
public static var allCases: [TextStyle] { Style.allCases.compactMap { Provider.style(for: $0) } }
public static func convert(font: UIFont) -> TextStyle {
guard let found = allCases.first(where: { font.fontName == $0.fontFace.fontName && font.pointSize == $0.pointSize} ) else {
return TextStyle(rawValue: "Custom\(font.fontName)", fontFace: .custom(font), pointSize: font.pointSize)

View File

@ -0,0 +1,246 @@
//
// Typography+StyleProvider.swift
// VDS
//
// Created by Matt Bruce on 9/25/24.
//
import Foundation
import UIKit
import VDSCoreTokens
extension TextStyle {
// Class responsible for providing the correct TextStyles based on language
public class Provider {
// Base styles for English (default)
private static let baseStyles: [Style: TextStyle] = [
.boldFeatureXLarge: TextStyle(rawValue: Style.boldFeatureXLarge.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)),
.featureXLarge: TextStyle(rawValue: Style.featureXLarge.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -4)),
.boldFeatureLarge: TextStyle(rawValue: Style.boldFeatureLarge.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)),
.featureLarge: TextStyle(rawValue: Style.featureLarge.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -6: -2)),
.boldFeatureMedium: TextStyle(rawValue: Style.boldFeatureMedium.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2)),
.featureMedium: TextStyle(rawValue: Style.featureMedium.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -4: -2)),
.boldFeatureSmall: TextStyle(rawValue: Style.boldFeatureSmall.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.featureSmall: TextStyle(rawValue: Style.featureSmall.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.boldFeatureXSmall: TextStyle(rawValue: Style.boldFeatureXSmall.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.featureXSmall: TextStyle(rawValue: Style.featureXSmall.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.boldTitle2XLarge: TextStyle(rawValue: Style.boldTitle2XLarge.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.title2XLarge: TextStyle(rawValue: Style.title2XLarge.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40,
letterSpacing: VDSTypography.letterSpacingSemiwide,
edgeInsets: .bottom(UIDevice.isIPad ? -2: 0)),
.boldTitleXLarge: TextStyle(rawValue: Style.boldTitleXLarge.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36),
.titleXLarge: TextStyle(rawValue: Style.titleXLarge.rawValue,
fontFace: .dsLight,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36,
letterSpacing: VDSTypography.letterSpacingSemiwide),
.boldTitleLarge: TextStyle(rawValue: Style.boldTitleLarge.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28),
.titleLarge: TextStyle(rawValue: Style.titleLarge.rawValue,
fontFace: UIDevice.isIPad ? .dsLight : .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28,
letterSpacing: UIDevice.isIPad ? VDSTypography.letterSpacingSemiwide : 0),
.boldTitleMedium: TextStyle(rawValue: Style.boldTitleMedium.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24),
.titleMedium: TextStyle(rawValue: Style.titleMedium.rawValue,
fontFace: .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24),
.boldTitleSmall: TextStyle(rawValue: Style.boldTitleSmall.rawValue,
fontFace: .edsBold,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20),
.titleSmall: TextStyle(rawValue: Style.titleSmall.rawValue,
fontFace: .edsRegular,
pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16,
lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20),
.boldBodyLarge: TextStyle(rawValue: Style.boldBodyLarge.rawValue,
fontFace: .edsBold,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing: VDSTypography.letterSpacingWide),
.bodyLarge: TextStyle(rawValue: Style.bodyLarge.rawValue,
fontFace: .edsRegular,
pointSize: VDSTypography.fontSizeBody16,
lineHeight: VDSTypography.lineHeightBody20,
letterSpacing:VDSTypography.letterSpacingWide),
.boldBodyMedium: TextStyle(rawValue: Style.boldBodyMedium.rawValue,
fontFace: .edsBold,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide),
.bodyMedium: TextStyle(rawValue: Style.bodyMedium.rawValue,
fontFace: .edsRegular,
pointSize: VDSTypography.fontSizeBody14,
lineHeight: VDSTypography.lineHeightBody18,
letterSpacing: VDSTypography.letterSpacingWide),
.boldBodySmall: TextStyle(rawValue: Style.boldBodySmall.rawValue,
fontFace: .etxBold,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16),
.bodySmall: TextStyle(rawValue: Style.bodySmall.rawValue,
fontFace: .etxRegular,
pointSize: VDSTypography.fontSizeBody12,
lineHeight: VDSTypography.lineHeightBody16),
.boldMicro: TextStyle(rawValue: Style.boldMicro.rawValue,
fontFace: .etxBold,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16),
.micro: TextStyle(rawValue: Style.micro.rawValue,
fontFace: .etxRegular,
pointSize: VDSTypography.fontSizeMicro11,
lineHeight: VDSTypography.lineHeightMicro16)
]
// Spanish lineHeight overrides
private static let spanishLineHeightOverrides: [Style: CGFloat] = [
.boldFeatureXLarge: UIDevice.isIPad ? 156 : 104,
.featureXLarge: UIDevice.isIPad ? 156 : 104,
.boldFeatureLarge: UIDevice.isIPad ? 140 : 88,
.featureLarge: UIDevice.isIPad ? 140 : 88,
.boldFeatureMedium: UIDevice.isIPad ? 104 : 72,
.featureMedium: UIDevice.isIPad ? 104 : 72,
.boldFeatureSmall: UIDevice.isIPad ? 88 : 56,
.featureSmall: UIDevice.isIPad ? 88 : 56,
.boldFeatureXSmall: UIDevice.isIPad ? 72 : 48,
.featureXSmall: UIDevice.isIPad ? 72 : 48,
.boldTitle2XLarge: UIDevice.isIPad ? 72 : 48,
.title2XLarge: UIDevice.isIPad ? 72 : 48,
.boldTitleXLarge: UIDevice.isIPad ? 56 : 36,
.titleXLarge: UIDevice.isIPad ? 56 : 36
]
// Cache for the current styles based on the current language
private static var currentStyles: [Style: TextStyle] = [:]
// Function to get the style with conditional lineHeight adjustment
static func style(for key: Style) -> TextStyle {
DispatchQueue.once(block: { TextStyle.Provider.initialize() })
guard let style = currentStyles[key] else {
fatalError("TextStyle for \(key.rawValue) is not defined.")
}
return style
}
// Update current styles only once when language changes
static func updateCurrentStyles() {
// Start with the base styles
currentStyles = baseStyles
// If the language is Spanish, apply the lineHeight overrides
if LanguageManager.currentLanguage == .spanish {
for (styleKey, spanishLineHeight) in spanishLineHeightOverrides {
if var style = currentStyles[styleKey] {
style = TextStyle(
rawValue: style.rawValue,
fontFace: style.fontFace,
pointSize: style.pointSize,
lineHeight: spanishLineHeight, // Apply the Spanish lineHeight
letterSpacing: style.letterSpacing,
edgeInsets: style.edgeInsets
)
currentStyles[styleKey] = style
}
}
}
}
// Initial setup to populate the current styles based on the initial language
static func initialize() {
updateCurrentStyles()
Style.allCases.forEach { style in
let found = Provider.currentStyles[style]
assert(found != nil, "\(style.rawValue) has not been set in the TextStyleProvider.baseStyles")
}
}
}
}