vds_ios/VDS/Components/Icon/Icon.swift
Matt Bruce 6bf3e19ebe added @objcMembers to all classes
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-25 10:53:26 -05:00

146 lines
4.8 KiB
Swift

//
// Icon.swift
// VDS
//
// Created by Matt Bruce on 1/9/23.
//
import Foundation
import UIKit
import VDSCoreTokens
import Combine
/// An icon is a graphical element that conveys information at a glance. It helps orient
/// a customer, explain functionality and draw attention to interactive elements. Icons
/// should have a functional purpose and should never be used for decoration.
@objcMembers
@objc(VDSIcon)
open class Icon: 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 dimensions: CGSize {
guard let customSize else { return size.dimensions }
return .init(width: customSize, height: customSize)
}
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
/// UIImageView used to render the icon.
open var imageView = UIImageView().with {
$0.isAccessibilityElement = false
$0.translatesAutoresizingMaskIntoConstraints = false
$0.contentMode = .scaleAspectFill
$0.clipsToBounds = true
}
/// Color of the icon.
open var color: UIColor = VDSColor.paletteBlack {
didSet {
if let hex = color.hexString, !UIColor.isVDSColor(color: color) {
print("icon.color is not a VDSColor. Hex: \(hex) is not a supported color")
}
colorConfiguration = SurfaceColorConfiguration(color, color)
}
}
open var colorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) { didSet { setNeedsUpdate() } }
/// Size of the icon.
open var size: Size = .medium { didSet { setNeedsUpdate() } }
/// This will be used to render the icon with corresponding name.
open var name: Name? { didSet { setNeedsUpdate() } }
/// A custom size of the icon.
open var customSize: Int? { didSet { setNeedsUpdate() } }
/// The natural size for the receiving view, considering only properties of the view itself.
open override var intrinsicContentSize: CGSize { dimensions }
//functions
//--------------------------------------------------
// 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()
setContentCompressionResistancePriority(.required, for: .vertical)
setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .horizontal)
setContentHuggingPriority(.required, for: .horizontal)
addSubview(imageView)
imageView.pinToSuperView()
backgroundColor = .clear
isAccessibilityElement = true
accessibilityTraits = .none
accessibilityHint = "image"
bridge_accessibilityLabelBlock = { [weak self] in
guard let self else { return "" }
return name?.rawValue ?? "icon"
}
}
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
//get the color for the image
let imageColor = colorConfiguration.getColor(surface)
//get the image name
//set the image
if let name, let image = UIImage.image(for: name, color: imageColor) {
imageView.image = image
} else {
imageView.image = nil
}
invalidateIntrinsicContentSize()
}
/// Resets to default settings.
open override func reset() {
super.reset()
color = VDSColor.paletteBlack
imageView.image = nil
}
}
extension UIImage {
/// UIImage helper for finding images based on the Icon.Name which uses the internal BundleManager.
/// - Parameters:
/// - name: Icon.Name rawRepresentable.
/// - color: Color to Tint the image with
/// - renderingMode: UIImage Rendering mode.
/// - Returns: UIImage for this proecess
public static func image(for iconName: Icon.Name, color: UIColor? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage? {
image(representing: iconName, color: color, renderingMode: renderingMode)
}
}