Merge branch 'refactor/titleLockup' into 'develop'

refactor TextStyles to use StandardStyle for models and rules

See merge request BPHV_MIPS/vds_ios!85
This commit is contained in:
Bruce, Matt R 2023-06-29 20:33:07 +00:00
commit 7464814735
21 changed files with 441 additions and 280 deletions

View File

@ -44,6 +44,7 @@
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 */; };
EA513A952A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */; };
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA596ABC2A16B4EC00300C4B /* Tab.swift */; };
EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA596ABE2A16B4F500300C4B /* Tabs.swift */; };
EA5E304C294CBDD00082B959 /* TileContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E304B294CBDD00082B959 /* TileContainer.swift */; };
@ -177,6 +178,7 @@
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>"; };
EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupStyleConfiguration.swift; sourceTree = "<group>"; };
EA596ABC2A16B4EC00300C4B /* Tab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tab.swift; sourceTree = "<group>"; };
EA596ABE2A16B4F500300C4B /* Tabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tabs.swift; sourceTree = "<group>"; };
EA5E304B294CBDD00082B959 /* TileContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainer.swift; sourceTree = "<group>"; };
@ -569,6 +571,7 @@
EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */,
EA985BEB2968A91200F2FF2E /* TitleLockupTitleModel.swift */,
EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */,
EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */,
);
path = TitleLockup;
sourceTree = "<group>";
@ -795,7 +798,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1340;
LastUpgradeCheck = 1430;
TargetAttributes = {
EA33616B288B19200071C351 = {
CreatedOnToolsVersion = 13.4.1;
@ -917,6 +920,7 @@
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */,
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */,
EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */,
EA513A952A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift in Sources */,
44604AD729CE196600E62B51 /* Line.swift in Sources */,
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
@ -1105,13 +1109,15 @@
isa = XCBuildConfiguration;
buildSettings = {
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 24;
CURRENT_PROJECT_VERSION = 25;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@ -1123,6 +1129,8 @@
"@loader_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.vds;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
@ -1138,13 +1146,15 @@
isa = XCBuildConfiguration;
buildSettings = {
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 24;
CURRENT_PROJECT_VERSION = 25;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@ -1156,6 +1166,8 @@
"@loader_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.vds;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;

View File

@ -368,7 +368,7 @@ open class BadgeIndicator: View {
let frame = badgeView.frame
//default calculation if a dotSize isn't given
var dot: CGFloat = frame.width * 0.1875
var dot: CGFloat = frame.height * 0.1875
if let dotSize, dotSize < frame.width, dotSize < frame.height {
dot = dotSize
}

View File

@ -89,14 +89,7 @@ open class TextLinkCaret: ButtonBase {
//--------------------------------------------------
override open var intrinsicContentSize: CGSize {
//get the labels size, if not the button
let size = titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
var itemWidth = size.width
if let caretWidth = imageAttribute?.width {
itemWidth += caretWidth
}
return CGSize(width: itemWidth, height: size.height)
return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
}
open override func updateView() {

View File

@ -21,30 +21,30 @@ extension Icon {
public init(name: String){
self.rawValue = name
}
public static let checkmark = Name(name: "checkmark")
internal static let checkmarkBold = Name(name: "checkmark-bold")
public static let checkmarkAlt = Name(name: "checkmark-alt")
internal static let checkmarkAltBold = Name(name: "checkmark-alt-bold")
public static let close = Name(name: "close")
internal static let checkmarkBold = Name(name: "checkmark-bold")
internal static let closeBold = Name(name: "close-bold")
public static let error = Name(name: "error")
internal static let errorBold = Name(name: "error-bold")
public static let info = Name(name: "info")
internal static let infoBold = Name(name: "info-bold")
public static let multipleDocuments = Name(name: "multiple-documents")
public static let leftArrow = Name(name: "left-arrow")
public static let leftCaret = Name(name: "left-caret")
internal static let leftCaretBold = Name(name: "left-caret-bold")
internal static let paginationLeftArrow = Name(name: "pagination-left-arrow")
public static let rightArrow = Name(name: "right-arrow")
public static let rightCaret = Name(name: "right-caret")
internal static let paginationLeftCaret = Name(name: "pagination-left-caret")
internal static let rightCaretBold = Name(name: "right-caret-bold")
internal static let paginationRightArrow = Name(name: "pagination-right-arrow")
public static let warning = Name(name: "warning")
internal static let paginationRightCaret = Name(name: "pagination-right-caret")
internal static let verizonUp = Name(name: "verizon-up")
internal static let warningBold = Name(name: "warning-bold")
public static let checkmark = Name(name: "checkmark")
public static let checkmarkAlt = Name(name: "checkmark-alt")
public static let close = Name(name: "close")
public static let error = Name(name: "error")
public static let info = Name(name: "info")
public static let multipleDocuments = Name(name: "multiple-documents")
public static let leftArrow = Name(name: "left-arrow")
public static let leftCaret = Name(name: "left-caret")
public static let rightArrow = Name(name: "right-arrow")
public static let rightCaret = Name(name: "right-caret")
public static let warning = Name(name: "warning")
}
}

View File

@ -73,7 +73,7 @@ extension Tabs {
private var leadingSpace: CGFloat {
guard orientation == .vertical else { return 0 }
return size == .medium ? VDSLayout.Spacing.space4X.value : VDSLayout.Spacing.space6X.value
return VDSLayout.Spacing.space4X.value
}
private var otherSpace: CGFloat {

View File

@ -70,65 +70,50 @@ open class Tilelet: TileContainer {
}
open var titleLockup = TitleLockup().with {
let configs = [
TextStyle.DeviceSpacingConfig([.titleSmall, .boldTitleSmall],
neighboring: [
.bodySmall, .boldBodySmall,
.bodyMedium, .boldBodyMedium
],
spacing: 8.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.titleMedium, .boldTitleMedium,
.titleLarge, .boldTitleLarge],
neighboring: [
.bodySmall, .boldBodySmall,
.bodyMedium, .boldBodyMedium,
.bodyLarge, .boldBodyLarge],
spacing: 8.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.titleXLarge, .boldTitleXLarge],
neighboring: [
.bodySmall, .boldBodySmall,
.bodyMedium, .boldBodyMedium,
.bodyLarge, .boldBodyLarge,
.titleMedium, .boldTitleMedium
],
spacing: 12.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.titleSmall, .boldTitleSmall,
.titleMedium, .boldTitleMedium],
neighboring: [
.bodySmall, .boldBodySmall,
.bodyMedium, .boldBodyMedium,
.bodyLarge, .boldBodyLarge
],
spacing: 8.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.titleLarge, .boldTitleLarge],
neighboring: [
.bodySmall, .boldBodySmall,
.bodyMedium, .boldBodyMedium,
.bodyLarge, .boldBodyLarge,
.titleSmall, .boldTitleSmall
],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.titleXLarge, .boldTitleXLarge],
neighboring: [
.bodyLarge, .boldBodyLarge,
.titleMedium, .boldTitleMedium
],
spacing: 16.0,
deviceType: .iPad)
]
$0.bottomTextStyleSpacingConfig = TextStyle.SpacingConfig(configs: configs)
$0.standardStyleConfiguration = .init(styleConfigurations: [
.init(deviceType: .iPhone,
titleStandardStyles: [.titleSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleMedium, .titleLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleXLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleMedium],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space3X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleSmall, .titleMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleSmall],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space3X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleXLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.titleMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space4X.value)
])
])
}
open var badge = Badge().with {
@ -332,10 +317,6 @@ open class Tilelet: TileContainer {
titleLockup.titleModel = titleModel?.toTitleLockupTitleModel()
titleLockup.subTitleModel = subTitleModel?.toTitleLockupSubTitleModel()
if let style = subTitleModel?.textStyle.value {
titleLockup.otherTextStyle = style
}
if titleLockupContainerView.superview == nil {
stackView.insertArrangedSubview(titleLockupContainerView, at: badgeContainerView.superview == nil ? 0 : 1)
setNeedsLayout()

View File

@ -12,21 +12,18 @@ extension Tilelet {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
public enum TextStyle: String, EnumSubset {
public enum StandardStyle: String, EnumSubset {
case bodyLarge
case boldBodyLarge
case bodyMedium
case boldBodyMedium
case bodySmall
case boldBodySmall
public var defaultValue: TitleLockup.OtherTextStyle { .bodySmall }
public var defaultValue: TitleLockup.OtherStandardStyle { .bodySmall }
}
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var text: String = ""
public var textStyle: TextStyle = .bodySmall
public var standardStyle: StandardStyle = .bodySmall
public var textAttributes: [any LabelAttributeModel]?
public var textColor: Use = .primary
@ -36,11 +33,11 @@ extension Tilelet {
public init(text: String,
textColor: Use = .primary,
textAttributes: [any LabelAttributeModel]? = nil,
textStyle: TextStyle = .bodySmall) {
standardStyle: StandardStyle = .bodySmall) {
self.text = text
self.textAttributes = textAttributes
self.textColor = textColor
self.textStyle = textStyle
self.standardStyle = standardStyle
}
//--------------------------------------------------
@ -48,6 +45,7 @@ extension Tilelet {
//--------------------------------------------------
public func toTitleLockupSubTitleModel() -> TitleLockup.SubTitleModel {
TitleLockup.SubTitleModel(text: text,
standardStyle: standardStyle.value,
textColor: textColor,
textAttributes: textAttributes)
}

View File

@ -12,44 +12,39 @@ extension Tilelet {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
public enum TextStyle: String, EnumSubset {
public enum StandardStyle: String, EnumSubset {
case titleXLarge
case boldTitleXLarge
case titleLarge
case boldTitleLarge
case titleMedium
case boldTitleMedium
case titleSmall
case boldTitleSmall
public var defaultValue: TitleLockup.TitleTextStyle { .boldTitleSmall }
public var defaultValue: TitleLockup.TitleStandardStyle { .titleSmall }
}
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var text: String = ""
public var textAttributes: [any LabelAttributeModel]?
public var textStyle: TextStyle = .boldTitleSmall
public var standardStyle: StandardStyle = .titleSmall
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public init(text: String,
textAttributes: [any LabelAttributeModel]? = nil,
textStyle: TextStyle = .boldTitleSmall) {
standardStyle: StandardStyle = .titleSmall) {
self.text = text
self.textAttributes = textAttributes
self.textStyle = textStyle
self.standardStyle = standardStyle
}
//--------------------------------------------------
// MARK: - Public Functions
//--------------------------------------------------
public func toTitleLockupTitleModel() -> TitleLockup.TitleModel {
TitleLockup.TitleModel(text: text,
textAttributes: textAttributes,
textStyle: textStyle.value)
standardStyle: standardStyle.value)
}
}
}

View File

@ -50,138 +50,114 @@ open class TitleLockup: View {
// MARK: - Configuration Properties
//--------------------------------------------------
// Sizes are from InVision design specs.
open var topTextStyleSpacingConfig: TextStyle.SpacingConfig = {
let configs = [
TextStyle.DeviceSpacingConfig([.boldTitleLarge, .titleLarge],
neighboring: [.bodySmall, .bodyMedium, .bodyLarge],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitleXLarge, .titleXLarge],
neighboring: [.titleMedium, .bodyLarge],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.titleMedium, .titleLarge],
spacing: 16.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.bodyLarge],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall, .boldFeatureMedium, .featureMedium],
neighboring: [.titleMedium, .titleLarge],
spacing: 16.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall, .boldFeatureMedium, .featureMedium],
neighboring: [.bodyLarge],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitleXLarge, .titleXLarge],
neighboring: [.bodyLarge, .bodyMedium, .bodySmall, .titleMedium],
spacing: 12.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.bodyLarge, .bodyMedium, .titleMedium],
spacing: 12.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall],
neighboring: [.titleLarge, .bodyLarge],
spacing: 12.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureMedium, .featureMedium],
neighboring: [.titleLarge, .titleXLarge],
spacing: 16.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureMedium, .featureMedium],
neighboring: [.bodyLarge],
spacing: 12.0,
deviceType: .iPhone)
]
return TextStyle.SpacingConfig(configs: configs)
}()
open var bottomTextStyleSpacingConfig: TextStyle.SpacingConfig = {
let configs = [
TextStyle.DeviceSpacingConfig([.boldTitleLarge, .titleLarge],
neighboring: [.bodySmall, .bodyMedium, .bodyLarge],
spacing: 12.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitleXLarge, .titleXLarge],
neighboring: [.titleMedium, .bodyLarge],
spacing: 16.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.titleMedium, .titleLarge],
spacing: 24.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.bodyLarge],
spacing: 24.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall, .boldFeatureMedium, .featureMedium],
neighboring: [.titleMedium, .titleLarge],
spacing: 24.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall, .boldFeatureMedium, .featureMedium],
neighboring: [.bodyLarge],
spacing: 24.0,
deviceType: .iPad),
TextStyle.DeviceSpacingConfig([.boldTitleXLarge, .titleXLarge],
neighboring: [.bodyLarge, .bodyMedium, .bodySmall, .titleMedium],
spacing: 12.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldTitle2XLarge, .title2XLarge, .boldFeatureXSmall, .featureXSmall],
neighboring: [.bodyLarge, .bodyMedium, .titleMedium],
spacing: 16,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureSmall, .featureSmall],
neighboring: [.titleLarge, .bodyLarge],
spacing: 16.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureMedium, .featureMedium],
neighboring: [.titleLarge, .titleXLarge],
spacing: 24.0,
deviceType: .iPhone),
TextStyle.DeviceSpacingConfig([.boldFeatureMedium, .featureMedium],
neighboring: [.bodyLarge],
spacing: 24.0,
deviceType: .iPhone)
]
return TextStyle.SpacingConfig(configs: configs)
}()
open var standardStyleConfiguration: StandardStyleConfigurationProvider = StandardStyleConfigurationProvider(styleConfigurations: [
.init(deviceType: .iPad,
titleStandardStyles: [.titleSmall, .titleMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleSmall],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space3X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleXLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.titleMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space4X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.title2XLarge, .featureXSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value),
.init(otherStandardStyles: [.titleMedium, .titleLarge],
topSpacing: VDSLayout.Spacing.space4X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value),
]),
.init(deviceType: .iPad,
titleStandardStyles: [.featureSmall, .featureMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.titleLarge, .titleMedium],
topSpacing: VDSLayout.Spacing.space4X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value),
.init(otherStandardStyles: [.bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value),
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleMedium, .titleLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleXLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge, .bodySmall, .bodyMedium, .titleMedium],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space3X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.title2XLarge, .featureXSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge, .bodyMedium, .titleMedium],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space4X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.featureSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.titleLarge, .bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space4X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.featureMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.titleLarge, .titleXLarge],
topSpacing: VDSLayout.Spacing.space4X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value),
.init(otherStandardStyles: [.bodyLarge],
topSpacing: VDSLayout.Spacing.space3X.value,
bottomSpacing: VDSLayout.Spacing.space6X.value)
]),
])
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
open var textPosition: TextPosition = .left { didSet { setNeedsUpdate() }}
//style
open var otherTextStyle: OtherTextStyle = UIDevice.isIPad ? .bodyLarge : .bodyMedium {
didSet {
setNeedsUpdate()
}
}
//first row
open var eyebrowLabel = Label().with {
$0.setContentCompressionResistancePriority(.required, for: .vertical)
@ -227,11 +203,20 @@ open class TitleLockup: View {
eyebrowModel = nil
titleModel = nil
subTitleModel = nil
otherTextStyle = UIDevice.isIPad ? .bodyLarge : .bodyMedium
shouldUpdateView = true
setNeedsUpdate()
}
private var otherStandardStyle: OtherStandardStyle {
if let subTitleModel, !subTitleModel.text.isEmpty {
return subTitleModel.standardStyle
} else if let eyebrowModel, !eyebrowModel.text.isEmpty {
return eyebrowModel.standardStyle
} else {
return .bodyLarge
}
}
//--------------------------------------------------
// MARK: - State
//--------------------------------------------------
@ -242,11 +227,21 @@ open class TitleLockup: View {
var eyebrowTextIsEmpty = true
var titleTextIsEmpty = true
var subTitleTextIsEmpty = true
var topSpacing: CGFloat = 0.0
var bottomSpacing: CGFloat = 0.0
//get the spacing based on the title style and other style used for eyebrow and subtitle
if let titleModel,
let config = standardStyleConfiguration.spacing(for: titleModel.standardStyle, otherStandardStyle: otherStandardStyle) {
topSpacing = config.topSpacing
bottomSpacing = config.bottomSpacing
}
if let eyebrowModel, !eyebrowModel.text.isEmpty {
eyebrowTextIsEmpty = false
eyebrowLabel.textPosition = allLabelsTextPosition
eyebrowLabel.textStyle = otherTextStyle.value
eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular
eyebrowLabel.text = eyebrowModel.text
eyebrowLabel.attributes = eyebrowModel.textAttributes
eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines
@ -258,7 +253,7 @@ open class TitleLockup: View {
if let titleModel, !titleModel.text.isEmpty {
titleTextIsEmpty = false
titleLabel.textPosition = allLabelsTextPosition
titleLabel.textStyle = titleModel.textStyle.value
titleLabel.textStyle = titleModel.textStyle
titleLabel.text = titleModel.text
titleLabel.attributes = titleModel.textAttributes
titleLabel.numberOfLines = titleModel.numberOfLines
@ -270,7 +265,7 @@ open class TitleLockup: View {
if let subTitleModel, !subTitleModel.text.isEmpty {
subTitleTextIsEmpty = false
subTitleLabel.textPosition = allLabelsTextPosition
subTitleLabel.textStyle = otherTextStyle.value
subTitleLabel.textStyle = otherStandardStyle.value.regular
subTitleLabel.text = subTitleModel.text
subTitleLabel.attributes = subTitleModel.textAttributes
subTitleLabel.numberOfLines = subTitleModel.numberOfLines
@ -281,16 +276,15 @@ open class TitleLockup: View {
}
//if both first 2 rows not empty set spacing
if let eyebrowModel, let titleModel, !eyebrowModel.text.isEmpty, !titleModel.text.isEmpty {
stackView.spacing = topTextStyleSpacingConfig.spacing(for: titleModel.textStyle.value, neighboring: otherTextStyle.value)
if !eyebrowTextIsEmpty && !titleTextIsEmpty {
stackView.spacing = topSpacing
} else {
stackView.spacing = 0.0
}
//if either first 2 rows not empty and subtile not empty, create space else collapse
if let titleModel, (!eyebrowTextIsEmpty || !titleTextIsEmpty) && !subTitleTextIsEmpty {
let bottomSpace = bottomTextStyleSpacingConfig.spacing(for: titleModel.textStyle.value, neighboring: otherTextStyle.value)
stackView.setCustomSpacing(bottomSpace, after: titleLabel)
if (!eyebrowTextIsEmpty || !titleTextIsEmpty) && !subTitleTextIsEmpty {
stackView.setCustomSpacing(bottomSpacing, after: titleLabel)
} else if (!eyebrowTextIsEmpty || !titleTextIsEmpty) && subTitleTextIsEmpty {
stackView.setCustomSpacing(0.0, after: titleLabel)
}
@ -300,5 +294,4 @@ open class TitleLockup: View {
titleLabel.isHidden = titleTextIsEmpty
subTitleLabel.isHidden = subTitleTextIsEmpty
}
}

View File

@ -10,15 +10,23 @@ import Foundation
extension TitleLockup {
public struct EyebrowModel {
public var text: String
public var isBold: Bool
public var textAttributes: [any LabelAttributeModel]?
public var standardStyle: OtherStandardStyle
public var numberOfLines: Int
public init(text: String,
isBold: Bool = false,
standardStyle: OtherStandardStyle = .bodyLarge,
textAttributes: [any LabelAttributeModel]? = nil,
numberOfLines: Int = 0) {
self.text = text
self.isBold = isBold
self.standardStyle = standardStyle
self.textAttributes = textAttributes
self.numberOfLines = numberOfLines
}
public var textStyle: TextStyle { isBold ? standardStyle.value.bold : standardStyle.value.regular }
}
}

View File

@ -0,0 +1,85 @@
//
// TitleLockupStandardStyleConfiguration.swift
// VDS
//
// Created by Matt Bruce on 6/29/23.
//
import Foundation
import UIKit
extension TitleLockup {
public struct StandardStyleConfigurationProvider {
public var styleConfigurations: [StandardStyleConfiguration]
public init(styleConfigurations: [StandardStyleConfiguration]) {
self.styleConfigurations = styleConfigurations
}
public func configuration(for titleStandardStyle: TitleStandardStyle) -> StandardStyleConfiguration? {
let deviceType: StandardStyleConfiguration.DeviceType = UIDevice.isIPad ? .iPad : .iPhone
guard let config: StandardStyleConfiguration = styleConfigurations.first(where: { return titleStandardStyle.isWithin($0.titleStandardStyles) && ($0.deviceType == deviceType || $0.deviceType == .all )}) else { return nil }
return config
}
public func isValid(otherStandardStyle: OtherStandardStyle, for titleStandardStyle: TitleStandardStyle) -> Bool {
guard let config = configuration(for: titleStandardStyle) else { return false }
return otherStandardStyle.isWithin(config.spacingConfigurations.flatMap {$0.otherStandardStyles})
}
public func spacing(for titleStandardStyle: TitleStandardStyle, otherStandardStyle: OtherStandardStyle) -> (otherStandardStyle: OtherStandardStyle, topSpacing: CGFloat, bottomSpacing: CGFloat)? {
guard let config = configuration(for: titleStandardStyle) else { return nil }
return config.styleSpacing(for: otherStandardStyle)
}
}
public struct StandardStyleConfiguration {
public enum DeviceType {
case iPhone, iPad, all
}
public var deviceType: DeviceType
public var titleStandardStyles:[TitleStandardStyle]
public var spacingConfigurations: [SpacingConfiguration]
public init(deviceType: DeviceType, titleStandardStyles: [TitleStandardStyle], spacingConfigurations: [SpacingConfiguration]) {
self.deviceType = deviceType
self.titleStandardStyles = titleStandardStyles
self.spacingConfigurations = spacingConfigurations
}
public var allOtherStandardStyles: [OtherStandardStyle] {
spacingConfigurations.flatMap {$0.otherStandardStyles}
}
public func styleSpacing(for otherStandardStyle: OtherStandardStyle) -> (otherStandardStyle: OtherStandardStyle, topSpacing: CGFloat, bottomSpacing: CGFloat) {
//set default return other style what you pass in
var realOtherStyle = otherStandardStyle
//flatten all of the other styles registered for the title styles
let allOtherStyles = spacingConfigurations.flatMap {$0.otherStandardStyles}
//get the default other style incase what is passed isn't within the registered collection
if let first = allOtherStyles.first, !realOtherStyle.isWithin(allOtherStyles) {
realOtherStyle = first
}
//get the config against the other style or return defaults
guard let styleSpacing = spacingConfigurations.first(where: {realOtherStyle.isWithin($0.otherStandardStyles)}) else {
return (realOtherStyle, VDSLayout.Spacing.space2X.value, VDSLayout.Spacing.space2X.value)
}
return (realOtherStyle, styleSpacing.topSpacing, styleSpacing.bottomSpacing)
}
}
public struct SpacingConfiguration {
public var otherStandardStyles: [OtherStandardStyle]
public var topSpacing: CGFloat
public var bottomSpacing: CGFloat
public init(otherStandardStyles: [OtherStandardStyle], topSpacing: CGFloat, bottomSpacing: CGFloat) {
self.otherStandardStyles = otherStandardStyles
self.topSpacing = topSpacing
self.bottomSpacing = bottomSpacing
}
}
}

View File

@ -10,18 +10,25 @@ import Foundation
extension TitleLockup {
public struct SubTitleModel {
public var text: String
public var standardStyle: OtherStandardStyle
public var textColor: Use
public var textAttributes: [any LabelAttributeModel]?
public var numberOfLines: Int
public init(text: String,
standardStyle: OtherStandardStyle = .bodyLarge,
textColor: Use = .primary,
textAttributes: [any LabelAttributeModel]? = nil,
numberOfLines: Int = 0) {
self.text = text
self.standardStyle = standardStyle
self.textColor = textColor
self.textAttributes = textAttributes
self.numberOfLines = numberOfLines
}
public var textStyle: TextStyle { standardStyle.value.regular }
}
}

View File

@ -11,46 +11,39 @@ extension TitleLockup {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
public enum TitleTextStyle: String, CaseIterable {
public enum TitleStandardStyle: String, CaseIterable {
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: TextStyle {.boldFeatureXSmall }
public var defaultValue: TextStyle.StandardStyle {.featureXSmall }
public var value: TextStyle {
TextStyle.textStyle(for: self.rawValue) ?? defaultValue
public var value: TextStyle.StandardStyle {
TextStyle.StandardStyle(rawValue: self.rawValue) ?? defaultValue
}
}
public enum OtherTextStyle: String, CaseIterable {
case bodyLarge
case boldBodyLarge
case bodyMedium
case boldBodyMedium
public enum OtherStandardStyle: String, CaseIterable {
case bodySmall
case boldBodySmall
case bodyMedium
case bodyLarge
case titleSmall
case titleMedium
case titleLarge
case titleXLarge
public var defaultValue: TextStyle {.bodyLarge }
public var defaultValue: TextStyle.StandardStyle { .bodyLarge }
public var value: TextStyle {
TextStyle.textStyle(for: self.rawValue) ?? defaultValue
public var value: TextStyle.StandardStyle {
TextStyle.StandardStyle(rawValue: self.rawValue) ?? defaultValue
}
}
}

View File

@ -11,17 +11,23 @@ extension TitleLockup {
public struct TitleModel {
public var text: String
public var textAttributes: [any LabelAttributeModel]?
public var textStyle: TitleTextStyle
public var isBold: Bool
public var standardStyle: TitleStandardStyle
public var numberOfLines: Int
public init(text: String,
textAttributes: [any LabelAttributeModel]? = nil,
textStyle: TitleTextStyle = .boldFeatureXSmall,
isBold: Bool = true,
standardStyle: TitleStandardStyle = .featureXSmall,
numberOfLines: Int = 0) {
self.text = text
self.isBold = isBold
self.textAttributes = textAttributes
self.textStyle = textStyle
self.standardStyle = standardStyle
self.numberOfLines = numberOfLines
}
public var textStyle: TextStyle { isBold ? standardStyle.value.bold : standardStyle.value.regular }
}
}

View File

@ -79,12 +79,14 @@ open class Toggle: Control, Changeable {
private var toggleColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.paletteGray44, forState: .normal)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
$0.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forState: .selected)
}
private var knobColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forState: .normal)
$0.setSurfaceColors(VDSColor.paletteGray95, VDSColor.paletteGray44, forState: .disabled)
$0.setSurfaceColors(VDSColor.paletteGray95, VDSColor.paletteGray44, forState: [.selected, .disabled])
$0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forState: .selected)
}

View File

@ -20,7 +20,8 @@ extension NSAttributedString {
extension NSMutableAttributedString {
public static func mutableText(for text: String, textStyle: TextStyle, textColor: UIColor, alignment: NSTextAlignment = .left, lineBreakMode: NSLineBreakMode) -> NSMutableAttributedString {
let startingAttributes = [NSAttributedString.Key.font: textStyle.font, NSAttributedString.Key.foregroundColor: textColor]
let font = textStyle.font
let startingAttributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor]
let attributedString = NSMutableAttributedString(string: text, attributes: startingAttributes)
//get the range
@ -35,13 +36,22 @@ extension NSMutableAttributedString {
paragraph.alignment = alignment
paragraph.lineBreakMode = lineBreakMode
if textStyle.lineSpacing > 0 {
paragraph.lineSpacing = textStyle.lineSpacing
}
//set lineHeight
if textStyle.lineHeight > 0.0 {
let lineHeight = textStyle.lineHeight
paragraph.maximumLineHeight = lineHeight
paragraph.minimumLineHeight = lineHeight
// if textStyle.lineHeight > textStyle.pointSize {
paragraph.maximumLineHeight = lineHeight
paragraph.minimumLineHeight = lineHeight
// paragraph.lineHeightMultiple = lineHeight / textStyle.pointSize
// } else {
// paragraph.lineHeightMultiple = lineHeight / font.pointSize
// }
}
attributedString.addAttribute( .baselineOffset, value: textStyle.baselineOffset, range: entireRange)
attributedString.addAttribute( .paragraphStyle, value: paragraph, range: entireRange)
return attributedString

View File

@ -7,6 +7,7 @@
import Foundation
import VDSColorTokens
import UIKit
extension VDSColor {
public static let paletteYellow62 = UIColor(hexString: "#FED60E")

View File

@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "verizon-up.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M19.8,19.8h-18v-18h18V19.8z M2.9,18.7h15.7V2.9H2.9V18.7z M12.4,8.1h-1.6v7.2h1.7v-2.6c0.4,0.5,0.9,0.7,1.5,0.7
c1.3-0.1,2.4-1.2,2.3-2.5c0-0.1,0-0.1,0-0.2C16.3,9.2,15.4,8,14,8c-0.6,0-1.2,0.3-1.6,0.8L12.4,8.1z M14.4,11.7
c-0.1,0.3-0.5,0.5-0.8,0.5c-0.8,0-1.2-0.6-1.2-1.4c0-0.8,0.4-1.5,1.1-1.5s1.1,0.6,1.1,1.5C14.6,11.1,14.6,11.4,14.4,11.7 M5.3,11.5
V8.1H7v3c0,0.6,0.3,0.9,0.8,0.9c0.5,0,0.9-0.4,0.9-0.9c0,0,0-0.1,0-0.1V8.1h1.7v5.1H8.8v-0.6l0,0c-0.4,0.5-1,0.8-1.6,0.8
c-1,0.1-1.8-0.6-1.9-1.6C5.3,11.7,5.3,11.6,5.3,11.5L5.3,11.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 898 B

View File

@ -1,6 +1,14 @@
1.0.26
=======
- CXTDT-426626 - Toggle - Disabled "on" state
- CXTDT-427165 - Text Link Caret - Container should not have left/right padding
1.0.25
=======
- TEMPORARY: Added BaselineOffset, LineSpacing to TextStyle
- Added Size, Width, Height, Horizontal/Vertical Padding + more to Badge Indicator
- CXTDT-424370 - Icons are fuzzy when resized
- CXTDT-426521 - Tabs - Vertical Tablet spacing
1.0.24
=======

View File

@ -29,6 +29,8 @@ public struct TextStyle: Equatable, RawRepresentable {
public let lineHeight: CGFloat
public let letterSpacing: CGFloat
public let fontFace: Font
public let lineSpacing: CGFloat
public let baselineOffset: CGFloat
public init?(rawValue: String) {
guard let style = TextStyle.textStyle(for: rawValue) else { return nil }
@ -37,14 +39,22 @@ public struct TextStyle: Equatable, RawRepresentable {
self.lineHeight = style.lineHeight
self.letterSpacing = style.letterSpacing
self.fontFace = style.fontFace
self.lineSpacing = style.lineSpacing
self.baselineOffset = style.baselineOffset
}
public init(rawValue: String, fontFace: Font, pointSize: CGFloat = 0.0, lineHeight: CGFloat = 0.0, letterSpacing: CGFloat = 0.0) {
public init(rawValue: String, fontFace: Font, pointSize: CGFloat = 0.0, lineHeight: CGFloat = 0.0, letterSpacing: CGFloat = 0.0, lineSpacing: CGFloat = 0.0, baselineOffset: CGFloat = 0.0) {
self.rawValue = rawValue
self.fontFace = fontFace
self.pointSize = pointSize
self.lineHeight = lineHeight
self.letterSpacing = letterSpacing
self.lineSpacing = lineSpacing
self.baselineOffset = baselineOffset
}
public var isBold: Bool {
rawValue.hasPrefix("bold")
}
}
@ -255,9 +265,43 @@ extension TextStyle {
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 {
@ -344,8 +388,8 @@ extension TextStyle {
}
}
extension TextStyle {
public func isWithin(_ collection: [TextStyle]) -> Bool {
extension RawRepresentable where Self.RawValue: Equatable {
public func isWithin(_ collection: [Self]) -> Bool {
(collection.first(where: {$0 == self}) != nil)
}
}