// // Tab.swift // VDS // // Created by Matt Bruce on 5/18/23. // import Foundation import VDSColorTokens import Combine public class TabItem: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- public var label: Label = Label() public var orientation: Tabs.Orientation = .horizontal { didSet { setNeedsUpdate() } } public var size: Tabs.Size = .medium { didSet { setNeedsUpdate() } } public var indicatorPosition: Tabs.IndicatorPosition = .bottom { didSet { setNeedsUpdate() } } public var onClick: (() -> Void)? { didSet { setNeedsUpdate() } } public var width: CGFloat? { didSet { setNeedsUpdate() } } public var selected: Bool = false { didSet { setNeedsUpdate() } } public var text: String? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var labelWidthConstraint: NSLayoutConstraint? private var labelLeadingConstraint: NSLayoutConstraint? private var labelTopConstraint: NSLayoutConstraint? private var labelBottomConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- private var textColorConfiguration: SurfaceColorConfiguration { selected ? textColorSelectedConfiguration : textColorNonSelectedConfiguration } private var textColorNonSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight) private var textColorSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) private var indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteRed, VDSColor.elementsPrimaryOndark) private var indicatorWidth: CGFloat = 4.0 //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- public override init(frame: CGRect) { super.init(frame: frame) } public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } required public convenience init() { self.init(frame: .zero) } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- override public func setup() { super.setup() addSubview(label) backgroundColor = .clear label.backgroundColor = .clear label.translatesAutoresizingMaskIntoConstraints = false label.pinTrailing() labelTopConstraint = label.topAnchor.constraint(equalTo: topAnchor, constant: 0) labelTopConstraint?.isActive = true labelBottomConstraint = label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0) labelBottomConstraint?.isActive = true labelLeadingConstraint = label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0) labelLeadingConstraint?.isActive = true labelWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 44.0) labelWidthConstraint?.isActive = true publisher(for: UITapGestureRecognizer()) .sink { [weak self] _ in self?.onClick?() }.store(in: &subscribers) } public override func updateView() { if orientation == .horizontal { label.textPosition = .center } else { label.textPosition = .left } label.text = text label.textStyle = size.textStyle label.textColor = textColorConfiguration.getColor(self) labelWidthConstraint?.isActive = false if let width { labelWidthConstraint = label.widthAnchor.constraint(equalToConstant: width) } else { labelWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 44.0) } labelWidthConstraint?.isActive = true var leadingSpace: CGFloat if orientation == .horizontal { leadingSpace = 0 } else { leadingSpace = size == .medium ? VDSLayout.Spacing.space4X.value : VDSLayout.Spacing.space6X.value } labelLeadingConstraint?.constant = leadingSpace var otherSpace: CGFloat if orientation == .horizontal { otherSpace = size == .medium ? VDSLayout.Spacing.space3X.value : VDSLayout.Spacing.space4X.value } else { otherSpace = VDSLayout.Spacing.space2X.value } labelTopConstraint?.constant = otherSpace labelBottomConstraint?.constant = -otherSpace setNeedsLayout() } public override func layoutSubviews() { super.layoutSubviews() removeBorders() if selected { var indicator: UIRectEdge = .left if orientation == .horizontal { indicator = indicatorPosition.value } addBorder(side: indicator, width: indicatorWidth, color: indicatorColorConfiguration.getColor(self)) } } }