// // TitleLockup.swift // VDS // // Created by Matt Bruce on 12/19/22. // import Foundation import UIKit import VDSColorTokens import Combine public enum TitleLockupTextPosition: String, Codable, CaseIterable { case left, center var labelTextPosition: TextPosition { switch self { case .left: return .left case .center: return .center } } } public enum TitleLockupitleTypographicalStyle: String, Codable, 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 typographicalStyle: TypographicalStyle { return TypographicalStyle(rawValue: self.rawValue) ?? .BoldFeatureXSmall } } public enum TitleLockupOtherTypographicalStyle: String, Codable, CaseIterable { case BodyLarge case BoldBodyLarge case BodyMedium case BoldBodyMedium case BodySmall case BoldBodySmall public var typographicalStyle: TypographicalStyle { return TypographicalStyle(rawValue: self.rawValue) ?? .BodyLarge } } @objc(VDSTitleLockup) open class TitleLockup: View { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(frame: .zero) } public override init(frame: CGRect) { super.init(frame: .zero) } public required init?(coder: NSCoder) { super.init(coder: coder) } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var stackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .vertical $0.distribution = .fill } //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- // Sizes are from InVision design specs. //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var textPosition: TitleLockupTextPosition = .left { didSet { didChange() }} //style open var titleTypograpicalStyle: TitleLockupitleTypographicalStyle = .BoldFeatureXSmall { didSet { didChange() }} open var otherTypograpicalStyle: TitleLockupOtherTypographicalStyle = .BodyLarge { didSet { didChange() }} //first row open var eyebrowLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) } open var eyebrowText: String = "" { didSet { didChange() }} open var eyebrowTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }} //second row open var titleLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) } open var titleText: String = "" { didSet { didChange() }} open var titleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }} //third row open var subTitleLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) } open var subTitleText: String = "" { didSet { didChange() }} open var subTitleTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }} open var subTitleColor: Use = .primary { didSet { didChange() }} //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- open override func setup() { super.setup() isAccessibilityElement = true accessibilityTraits = .button addSubview(stackView) stackView.spacing = 0.0 stackView.addArrangedSubview(eyebrowLabel) stackView.addArrangedSubview(titleLabel) stackView.addArrangedSubview(subTitleLabel) //pin stackview to edges stackView.pinToSuperView() } public override func reset() { super.reset() titleLabel.reset() eyebrowLabel.reset() subTitleLabel.reset() textPosition = .left eyebrowText = "" titleText = "" subTitleText = "" titleTypograpicalStyle = .BoldFeatureXSmall otherTypograpicalStyle = .BodyLarge } //-------------------------------------------------- // MARK: - State //-------------------------------------------------- open override func updateView() { super.updateView() let allLabelsTextPosition = textPosition.labelTextPosition eyebrowLabel.textPosition = allLabelsTextPosition eyebrowLabel.typograpicalStyle = otherTypograpicalStyle.typographicalStyle eyebrowLabel.text = eyebrowText eyebrowLabel.attributes = eyebrowTextAttributes eyebrowLabel.surface = surface titleLabel.textPosition = allLabelsTextPosition titleLabel.typograpicalStyle = titleTypograpicalStyle.typographicalStyle titleLabel.text = titleText titleLabel.attributes = titleTextAttributes titleLabel.surface = surface subTitleLabel.textPosition = allLabelsTextPosition subTitleLabel.typograpicalStyle = otherTypograpicalStyle.typographicalStyle subTitleLabel.text = subTitleText subTitleLabel.attributes = subTitleTextAttributes subTitleLabel.surface = surface subTitleLabel.disabled = subTitleColor == .secondary //if both first 2 rows not empty set spacing if !eyebrowText.isEmpty && !titleText.isEmpty { stackView.spacing = 12.0 } 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) } else if (!eyebrowText.isEmpty || !titleText.isEmpty) && subTitleText.isEmpty { stackView.setCustomSpacing(0.0, after: titleLabel) } } }