// // Badge.swift // VDS // // Created by Matt Bruce on 9/22/22. // import Foundation import UIKit import VDSColorTokens import VDSFormControlsTokens import Combine /// Badges are visual labels used to convey status or highlight supplemental information. @objc(VDSBadge) open class Badge: View { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- public enum FillColor: String, CaseIterable { case red, yellow, green, orange, blue, black, white } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.adjustsFontSizeToFitWidth = false $0.lineBreakMode = .byTruncatingTail $0.textPosition = .left $0.textStyle = .boldBodySmall } open var fillColor: FillColor = .red { didSet { didChange() }} open var text: String = "" { didSet { didChange() }} open var maxWidth: CGFloat? { didSet { didChange() }} open var numberOfLines: Int = 1 { didSet { didChange() }} //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- private var maxWidthConstraint: NSLayoutConstraint? private var minWidthConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- open override func setup() { super.setup() accessibilityElements = [label] layer.cornerRadius = VDSFormControls.borderradius addSubview(label) label.pinToSuperView(.init(top: 2, left: 4, bottom: 2, right: 4)) maxWidthConstraint = label.widthAnchor.constraint(lessThanOrEqualToConstant: 100) minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23) minWidthConstraint?.isActive = true } open override func reset() { super.reset() label.reset() label.lineBreakMode = .byTruncatingTail label.textPosition = .left label.textStyle = .boldBodySmall fillColor = .red text = "" maxWidth = nil numberOfLines = 1 } //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- private var backgroundColorConfig: AnyColorable = { let config = KeyedColorConfiguration(keyPath: \.fillColor) config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) config.setSurfaceColors(VDSColor.paletteYellow62, VDSColor.paletteYellow62, forKey: .yellow) config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen34, forKey: .green) config.setSurfaceColors(VDSColor.paletteOrange39, VDSColor.paletteOrange46, forKey: .orange) config.setSurfaceColors(VDSColor.paletteBlue35, VDSColor.paletteBlue45, forKey: .blue) config.setSurfaceColors(VDSColor.paletteBlack, VDSColor.paletteBlack, forKey: .black) config.setSurfaceColors(VDSColor.paletteWhite, VDSColor.paletteWhite, forKey: .white) return config.eraseToAnyColorable() }() private var textColorConfig = ViewColorConfiguration() public func updateTextColorConfig() { textColorConfig.reset() switch fillColor { case .red, .black: textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false) textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true) case .yellow, .white: textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false) textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true) case .orange, .green, .blue: textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false) textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true) } } //-------------------------------------------------- // MARK: - State //-------------------------------------------------- open override func updateView() { updateTextColorConfig() backgroundColor = backgroundColorConfig.getColor(self) label.textColorConfiguration = textColorConfig.eraseToAnyColorable() label.numberOfLines = numberOfLines label.text = text label.surface = surface label.disabled = disabled if let maxWidth = maxWidth, let minWidth = minWidthConstraint?.constant, maxWidth > minWidth { maxWidthConstraint?.constant = maxWidth maxWidthConstraint?.isActive = true } else { maxWidthConstraint?.isActive = false } } }