// // Footnote.swift // VDS // // Created by Kanamarlapudi, Vasavi on 21/08/24. // import Foundation import UIKit import VDSCoreTokens import Combine /// A footnote is text that provides supporting details, legal copy and links to related content. If exists at the bottom or "foot" of a page or section. @objcMembers @objc(VDSFootnote) open class Footnote: 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: - enums //-------------------------------------------------- /// Enum used to describe the kind of component. public enum Kind: String, DefaultValuing, CaseIterable { case primary, secondary /// The default kind is 'primary'. public static var defaultValue : Self { .secondary } /// Color configuation to Symbol and Text relative to kind. public var colorConfiguration: SurfaceColorConfiguration { switch self { case .primary: return SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) case .secondary: return SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) } } } /// Enum that represents the size availble for component. public enum Size: String, DefaultValuing, CaseIterable { case micro case small case large public static var defaultValue: Self { .micro } /// TextStyle relative to Size. public var textStyle: TextStyle.StandardStyle { switch self { case .micro: return .micro case .small: return .bodySmall case .large: return .bodyLarge } } } /// Enum used to describe the symboldType of component. public enum SymbolType: String, DefaultValuing, CaseIterable { case asterisk case doubleAsterisk case character public static var defaultValue: Self { .asterisk } /// TextStyle relative to Size. public var text: String { switch self { case .asterisk: return "*" case .doubleAsterisk: return "**" case .character: return "1." } } } /// Enum used to describe the width of a fixed value or percentage of parent's width. public enum Width { case percentage(CGFloat) case value(CGFloat) } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- /// Color to the component. The default kind is Secondary. open var kind: Kind = .defaultValue { didSet { setNeedsUpdate() } } /// Size of the component. The default size is Micro. open var size: Size = .defaultValue { didSet { setNeedsUpdate() } } /// If hideSymbol true, the component will show text without symbol. open var hideSymbol: Bool = false { didSet { setNeedsUpdate() } } /// Size of the component. The default size is Micro. open var symbolType: SymbolType = .defaultValue { didSet { setNeedsUpdate() } } /// Text of the footnote item. open var text: String? { didSet { setNeedsUpdate() } } /// Any percentage or pixel value and cannot exceed container size.. /// If there is a width that is larger than container size, the footnote will resize to container's width. open var width: Width? { get { _width } set { if let newValue { switch newValue { case .percentage(let percentage): if percentage <= 100.0 { _width = newValue } case .value(let value): if value > 0 { _width = newValue } } } else { _width = nil } setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var _width: Width? = nil internal var footnoteItem = UIStackView().with { $0.axis = .horizontal $0.spacing = VDSLayout.space1X $0.alignment = .top $0.distribution = .fillEqually } internal var symbolLabel = Label().with { $0.isAccessibilityElement = true } internal var footnoteItemLabel = Label().with { $0.isAccessibilityElement = true $0.lineBreakMode = .byWordWrapping } //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() addSubview(symbolLabel) symbolLabel.pinToSuperView() addSubview(footnoteItemLabel) footnoteItemLabel.pinToSuperView() } open override func setDefaults() { super.setDefaults() } /// Resets to default settings. open override func reset() { super.reset() } /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() symbolLabel.text = hideSymbol ? "" : symbolType.text footnoteItemLabel.text = text symbolLabel.surface = surface footnoteItemLabel.surface = surface } }