vds_ios/VDS/Components/Tooltip/Tooltip.swift
Matt Bruce 16d37e1c45 ONEAPP-5104 - Button Disabled Accessibility iOS
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2023-07-28 14:29:43 -05:00

194 lines
6.6 KiB
Swift

//
// Tooltip.swift
// VDS
//
// Created by Matt Bruce on 4/13/23.
//
import Foundation
import UIKit
import VDSColorTokens
import VDSFormControlsTokens
import Combine
@objc(VDSTooltip)
open class Tooltip: Control, TooltipLaunchable {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
public enum FillColor: String, CaseIterable {
case primary, secondary, brandHighlight
}
public enum Size: String, EnumSubset {
case small
case medium
public var defaultValue: Icon.Size { .small }
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private var widthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
private var infoImage = UIImage()
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
open var imageView = UIImageView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.contentMode = .scaleAspectFill
$0.clipsToBounds = true
}
open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }}
open var fillColor: FillColor = .primary { didSet { setNeedsUpdate() }}
open var size: Size = .medium { didSet { setNeedsUpdate() }}
open var title: String? { didSet { setNeedsUpdate() }}
open var content: String? { didSet { setNeedsUpdate() }}
open var contentView: UIView? { didSet { setNeedsUpdate() }}
//--------------------------------------------------
// MARK: - Configuration
//--------------------------------------------------
private var iconColorConfiguration: AnyColorable {
switch fillColor {
case .primary:
return primaryColorConfiguration.eraseToAnyColorable()
case .secondary:
return secondaryColorConfiguration.eraseToAnyColorable()
case .brandHighlight:
return brandHighlightColorConfiguration.eraseToAnyColorable()
}
}
private var primaryColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal)
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
}
private var secondaryColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forState: .normal)
$0.setSurfaceColors(VDSColor.paletteGray65, VDSColor.paletteGray65, forState: .highlighted)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
}
private var brandHighlightColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsBrandhighlight, VDSColor.elementsBrandhighlight, forState: .normal)
$0.setSurfaceColors(VDSColor.elementsBrandhighlight, VDSColor.elementsBrandhighlight, forState: .highlighted)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
}
//--------------------------------------------------
// 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: - Lifecycle
//--------------------------------------------------
open override func setup() {
super.setup()
if let image = BundleManager.shared.image(for: "info") {
infoImage = image
}
addSubview(imageView)
imageView.pinToSuperView()
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: size.value.dimensions.height)
heightConstraint?.isActive = true
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: size.value.dimensions.width)
widthConstraint?.isActive = true
backgroundColor = .clear
isAccessibilityElement = true
accessibilityTraits = .link
onClickSubscriber = publisher(for: .touchUpInside)
.sink(receiveValue: { [weak self] tooltip in
guard let self else { return}
self.presentTooltip(surface: tooltip.surface,
title: tooltip.title,
content: tooltip.content,
contentView: tooltip.contentView,
closeButtonText: tooltip.closeButtonText)
})
}
/// Resets back to this objects default settings.
open override func reset() {
super.reset()
shouldUpdateView = false
size = .medium
title = ""
content = ""
fillColor = .primary
closeButtonText = "Close"
imageView.image = nil
shouldUpdateView = true
setNeedsUpdate()
}
open override func updateView() {
super.updateView()
//set the dimensions
let dimensions = size.value.dimensions
heightConstraint?.constant = dimensions.height
widthConstraint?.constant = dimensions.width
//get the color for the image
let imageColor = iconColorConfiguration.getColor(self)
imageView.image = infoImage.withTintColor(imageColor)
}
open override func updateAccessibilityLabel() {
if isEnabled {
accessibilityTraits.remove(.notEnabled)
} else {
accessibilityTraits.insert(.notEnabled)
}
var label = title
if label == nil {
label = content
}
if let label {
accessibilityLabel = "Tooltip: \(label)"
}
}
}
// MARK: AppleGuidlinesTouchable
extension Tooltip: AppleGuidlinesTouchable {
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
}
}