// // TextLinkCaret.swift // VDS // // Created by Matt Bruce on 11/1/22. // import Foundation import UIKit import VDSColorTokens import VDSFormControlsTokens import Combine @objc(VDSTextLinkCaret) open class TextLinkCaret: ButtonBase { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- public enum IconPosition: String, CaseIterable { case left, right } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- open override var textStyle: TextStyle { TextStyle.boldBodyLarge } private var imageAttribute: CaretLabelAttribute? open override var attributes: [any LabelAttributeModel]? { guard let imageAttribute else { return nil } return [imageAttribute] } //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public override var availableSizes: [ButtonSize] { [.large] } open var iconPosition: IconPosition = .right { didSet { setNeedsUpdate() } } private var height: CGFloat { 44 } open override var textColor: UIColor { textColorConfiguration.getColor(self) } private var textColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) } //-------------------------------------------------- // 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: - Public Functions //-------------------------------------------------- open override func setup() { super.setup() accessibilityTraits = .link } /// Resets back to this objects default settings. open override func reset() { super.reset() iconPosition = .right text = nil } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- override open var intrinsicContentSize: CGSize { //get the labels size, if not the button return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize } open override func updateView() { imageAttribute = CaretLabelAttribute(tintColor: textColor, position: iconPosition) super.updateView() } } extension TextLinkCaret { struct CaretLabelAttribute: LabelAttributeModel { var id: UUID = .init() var location: Int = 0 var length: Int = 1 var tintColor: UIColor var position: IconPosition var spacerWidth: CGFloat = 4.0 var width: CGFloat { caretSize.width + spacerWidth } var caretSize: CGSize { Icon.Size.xsmall.dimensions } init(tintColor: UIColor, position: IconPosition) { self.tintColor = tintColor self.position = position } func setAttribute(on attributedString: NSMutableAttributedString) { let imageAttr = ImageLabelAttribute(location: location, imageName: "\(position.rawValue)-caret-bold", frame: .init(x: 0, y: 0, width: caretSize.width, height: caretSize.height), tintColor: tintColor) let spacer = NSAttributedString.spacer(for: spacerWidth) guard let image = try? imageAttr.getAttachment() else { return } if position == .right { attributedString.append(spacer) attributedString.append(NSAttributedString(attachment: image)) } else { attributedString.insert(NSAttributedString(attachment: image), at: 0) attributedString.insert(spacer, at: 1) } } func isEqual(_ equatable: CaretLabelAttribute) -> Bool { return id == equatable.id && range == equatable.range } } }