diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index a93607ed..55448bd7 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -89,7 +89,6 @@ open class TitleLockup: View { //-------------------------------------------------- // Sizes are from InVision design specs. - //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -97,7 +96,7 @@ open class TitleLockup: View { //style open var titleTypograpicalStyle: TitleLockupTitleTypographicalStyle = .BoldFeatureXSmall { didSet { didChange() }} - open var otherTypograpicalStyle: TitleLockupOtherTypographicalStyle = .BodyLarge { didSet { didChange() }} + open var otherTypograpicalStyle: TitleLockupOtherTypographicalStyle = UIDevice.isIPad ? .BodyLarge : .BodyMedium { didSet { didChange() }} //first row open var eyebrowLabel = Label().with { @@ -154,7 +153,7 @@ open class TitleLockup: View { titleTextAttributes = nil subTitleText = "" subTitleTextAttributes = nil - titleTextAttributes + titleTextAttributes = nil titleTypograpicalStyle = .BoldFeatureXSmall otherTypograpicalStyle = .BodyLarge @@ -189,16 +188,151 @@ open class TitleLockup: View { //if both first 2 rows not empty set spacing if !eyebrowText.isEmpty && !titleText.isEmpty { - stackView.spacing = 12.0 + stackView.spacing = getTopSpacing() } else { stackView.spacing = 0.0 } //if either first 2 rows not empty and subtile not empty, create space else collapse if (!eyebrowText.isEmpty || !titleText.isEmpty) && !subTitleText.isEmpty { - stackView.setCustomSpacing(24.0, after: titleLabel) + stackView.setCustomSpacing(getBottomSpacing(), after: titleLabel) } else if (!eyebrowText.isEmpty || !titleText.isEmpty) && subTitleText.isEmpty { stackView.setCustomSpacing(0.0, after: titleLabel) } } + + internal var topTypographicalStyleSpacingConfig: TypographicalStyleSpacingConfig = { + let configs = [ + TypographicalStyleDeviceSpacingConfig([.BoldTitleLarge, .TitleLarge], + neighboring: [.BodySmall, .BodyMedium, .BodyLarge], + spacing: 12.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge], + neighboring: [.TitleMedium, .BodyLarge], + spacing: 12.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.TitleMedium, .TitleLarge], + spacing: 16.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.BodyLarge], + spacing: 12.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium], + neighboring: [.TitleMedium, .TitleLarge], + spacing: 16.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium], + neighboring: [.BodyLarge], + spacing: 12.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge], + neighboring: [.BodyLarge, .BodyMedium, .BodySmall, .TitleMedium], + spacing: 12.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.BodyLarge, .BodyMedium, .TitleMedium], + spacing: 12.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall], + neighboring: [.TitleLarge, .BodyLarge], + spacing: 12.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium], + neighboring: [.TitleLarge, .TitleXLarge], + spacing: 16.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium], + neighboring: [.BodyLarge], + spacing: 12.0, + deviceType: .iPhone) + ] + return TypographicalStyleSpacingConfig(configs: configs) + }() + + internal var bottomTypographicalStyleSpacingConfig: TypographicalStyleSpacingConfig = { + let configs = [ + TypographicalStyleDeviceSpacingConfig([.BoldTitleLarge, .TitleLarge], + neighboring: [.BodySmall, .BodyMedium, .BodyLarge], + spacing: 12.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge], + neighboring: [.TitleMedium, .BodyLarge], + spacing: 16.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.TitleMedium, .TitleLarge], + spacing: 24.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.BodyLarge], + spacing: 24.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium], + neighboring: [.TitleMedium, .TitleLarge], + spacing: 24.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall, .BoldFeatureMedium, .FeatureMedium], + neighboring: [.BodyLarge], + spacing: 24.0, + deviceType: .iPad), + + TypographicalStyleDeviceSpacingConfig([.BoldTitleXLarge, .TitleXLarge], + neighboring: [.BodyLarge, .BodyMedium, .BodySmall, .TitleMedium], + spacing: 12.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldTitle2XLarge, .Title2XLarge, .BoldFeatureXSmall, .FeatureXSmall], + neighboring: [.BodyLarge, .BodyMedium, .TitleMedium], + spacing: 16, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureSmall, .FeatureSmall], + neighboring: [.TitleLarge, .BodyLarge], + spacing: 16.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium], + neighboring: [.TitleLarge, .TitleXLarge], + spacing: 24.0, + deviceType: .iPhone), + + TypographicalStyleDeviceSpacingConfig([.BoldFeatureMedium, .FeatureMedium], + neighboring: [.BodyLarge], + spacing: 24.0, + deviceType: .iPhone) + ] + return TypographicalStyleSpacingConfig(configs: configs) + }() + + open func getTopSpacing() -> CGFloat { + topTypographicalStyleSpacingConfig.spacing(for: titleTypograpicalStyle.value, neighboring: otherTypograpicalStyle.value) + } + + open func getBottomSpacing() -> CGFloat { + bottomTypographicalStyleSpacingConfig.spacing(for: titleTypograpicalStyle.value, neighboring: otherTypograpicalStyle.value) + } } + +extension TypographicalStyle { + func isWithin(_ collection: [TypographicalStyle]) -> Bool { + (collection.first(where: {$0 == self}) != nil) + } +} + diff --git a/VDS/Typography/Typography.swift b/VDS/Typography/Typography.swift index 86629d91..daecf91b 100644 --- a/VDS/Typography/Typography.swift +++ b/VDS/Typography/Typography.swift @@ -281,3 +281,36 @@ extension TypographicalStyle { } } } + +public struct TypographicalStyleSpacingConfig { + public var defaultSpacing: CGFloat = 8.0 + public var configs: [TypographicalStyleDeviceSpacingConfig] + + public func spacing(for style: TypographicalStyle, neighboring: TypographicalStyle) -> CGFloat { + let deviceType: TypographicalStyleDeviceSpacingConfig.DeviceType = UIDevice.isIPad ? .iPad : .iPhone + if let config = configs.first(where: + { style.isWithin($0.primaryStyles) && neighboring.isWithin($0.neighboringStyles) && + ($0.deviceType == deviceType || $0.deviceType == .all )}) + { + return config.spacing + } + return defaultSpacing + } +} + +public struct TypographicalStyleDeviceSpacingConfig { + public enum DeviceType { + case iPhone, iPad, all + } + public var spacing: CGFloat + public var deviceType: DeviceType = .iPhone + public var primaryStyles: [TypographicalStyle] + public var neighboringStyles: [TypographicalStyle] + + public init(_ primaryStyles: [TypographicalStyle], neighboring: [TypographicalStyle], spacing: CGFloat, deviceType: DeviceType = .iPhone) { + self.spacing = spacing + self.primaryStyles = primaryStyles + self.neighboringStyles = neighboring + self.deviceType = deviceType + } +}