Merge branch 'feature/buttonIcon' into 'develop'
initial cut for ButtonICon See merge request BPHV_MIPS/vds_ios!69
This commit is contained in:
commit
4479bad76d
@ -47,6 +47,8 @@
|
||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30522950DDA60082B959 /* TitleLockup.swift */; };
|
||||
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilelet.swift */; };
|
||||
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; };
|
||||
EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */; };
|
||||
EA8141102A127066004F60D2 /* VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410F2A127066004F60D2 /* VDSColor.swift */; };
|
||||
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; };
|
||||
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; };
|
||||
EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; };
|
||||
@ -61,7 +63,6 @@
|
||||
EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */; };
|
||||
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF4296C60C000F2FF2E /* Icon.swift */; };
|
||||
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF6296C665E00F2FF2E /* IconName.swift */; };
|
||||
EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF8296C710100F2FF2E /* IconColor.swift */; };
|
||||
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C1C296CD13600F2FF2E /* BundleManager.swift */; };
|
||||
EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C22296E033A00F2FF2E /* TextArea.swift */; };
|
||||
EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */; };
|
||||
@ -167,6 +168,8 @@
|
||||
EA5E30522950DDA60082B959 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
|
||||
EA5E3057295105A40082B959 /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = "<group>"; };
|
||||
EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = "<group>"; };
|
||||
EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = "<group>"; };
|
||||
EA81410F2A127066004F60D2 /* VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSColor.swift; sourceTree = "<group>"; };
|
||||
EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = "<group>"; };
|
||||
EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = "<group>"; };
|
||||
EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = "<group>"; };
|
||||
@ -181,7 +184,6 @@
|
||||
EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTextStyle.swift; sourceTree = "<group>"; };
|
||||
EA985BF4296C60C000F2FF2E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = "<group>"; };
|
||||
EA985BF6296C665E00F2FF2E /* IconName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconName.swift; sourceTree = "<group>"; };
|
||||
EA985BF8296C710100F2FF2E /* IconColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconColor.swift; sourceTree = "<group>"; };
|
||||
EA985C1C296CD13600F2FF2E /* BundleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleManager.swift; sourceTree = "<group>"; };
|
||||
EA985C22296E033A00F2FF2E /* TextArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextArea.swift; sourceTree = "<group>"; };
|
||||
EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletIconModels.swift; sourceTree = "<group>"; };
|
||||
@ -412,6 +414,7 @@
|
||||
EAB5FED329267EB300998C17 /* UIView.swift */,
|
||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */,
|
||||
EA985C662970C21600F2FF2E /* VDSLayout.swift */,
|
||||
EA81410F2A127066004F60D2 /* VDSColor.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -540,6 +543,14 @@
|
||||
path = Tilelet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA81410C2A0E8E52004F60D2 /* ButtonIcon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */,
|
||||
);
|
||||
path = ButtonIcon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA89200B28B530F0006B9984 /* RadioBox */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -552,8 +563,8 @@
|
||||
EA985BF3296C609E00F2FF2E /* Icon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA81410C2A0E8E52004F60D2 /* ButtonIcon */,
|
||||
EA985BF4296C60C000F2FF2E /* Icon.swift */,
|
||||
EA985BF8296C710100F2FF2E /* IconColor.swift */,
|
||||
EA985BF6296C665E00F2FF2E /* IconName.swift */,
|
||||
EA985C682971B90B00F2FF2E /* IconSize.swift */,
|
||||
);
|
||||
@ -810,6 +821,7 @@
|
||||
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
|
||||
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */,
|
||||
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */,
|
||||
EA8141102A127066004F60D2 /* VDSColor.swift in Sources */,
|
||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,
|
||||
@ -855,6 +867,7 @@
|
||||
EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */,
|
||||
EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */,
|
||||
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */,
|
||||
EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */,
|
||||
EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */,
|
||||
EA336171288B19200071C351 /* VDS.docc in Sources */,
|
||||
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */,
|
||||
@ -867,7 +880,6 @@
|
||||
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */,
|
||||
EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */,
|
||||
EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */,
|
||||
EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */,
|
||||
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
|
||||
EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */,
|
||||
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,
|
||||
|
||||
380
VDS/Components/Icon/ButtonIcon/ButtonIcon.swift
Normal file
380
VDS/Components/Icon/ButtonIcon/ButtonIcon.swift
Normal file
@ -0,0 +1,380 @@
|
||||
//
|
||||
// ButtonIcon.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 5/12/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
|
||||
@objc(VDSButtonIcon)
|
||||
open class ButtonIcon: Control {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Models
|
||||
//--------------------------------------------------
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
public enum Kind: String, CaseIterable {
|
||||
case ghost, lowContrast, highContrast
|
||||
}
|
||||
|
||||
public enum SurfaceType: String, CaseIterable {
|
||||
case colorFill, media
|
||||
}
|
||||
|
||||
public enum Size: String, EnumSubset {
|
||||
case large
|
||||
case small
|
||||
|
||||
public var defaultValue: Icon.Size { .large }
|
||||
|
||||
public var containerSize: CGFloat {
|
||||
switch self {
|
||||
case .large:
|
||||
return 44.0
|
||||
case .small:
|
||||
return 32.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var centerXConstraint: NSLayoutConstraint?
|
||||
private var centerYConstraint: NSLayoutConstraint?
|
||||
private var layoutGuideWidthConstraint: NSLayoutConstraint?
|
||||
private var layoutGuideHeightConstraint: NSLayoutConstraint?
|
||||
private var currentIconName: Icon.Name? {
|
||||
if let selectedIconName {
|
||||
return selectedIconName
|
||||
} else {
|
||||
return iconName
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var icon = Icon()
|
||||
|
||||
open var kind: Kind = .ghost { didSet { setNeedsUpdate() } }
|
||||
open var surfaceType: SurfaceType = .colorFill { didSet { setNeedsUpdate() } }
|
||||
open var iconName: Icon.Name? { didSet { setNeedsUpdate() } }
|
||||
open var selectedIconName: Icon.Name? { didSet { setNeedsUpdate() } }
|
||||
open var size: Size = .large { didSet { setNeedsUpdate() } }
|
||||
open var customSize: Int? { didSet { setNeedsUpdate() }}
|
||||
open var floating: Bool = false { didSet { setNeedsUpdate() } }
|
||||
open var fitToIcon: Bool = false { didSet { setNeedsUpdate() } }
|
||||
open var hideBorder: Bool = true { didSet { setNeedsUpdate() } }
|
||||
open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration
|
||||
//--------------------------------------------------
|
||||
private var iconColorConfig: AnyColorable {
|
||||
if selectedIconName != nil {
|
||||
return selectedIconColorConfig
|
||||
} else {
|
||||
if kind == .highContrast {
|
||||
return highContrastIconColorConfig
|
||||
} else {
|
||||
return standardIconColorConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var currentConfiguration: any Configuration {
|
||||
switch kind {
|
||||
case .ghost:
|
||||
return GhostConfiguration()
|
||||
|
||||
case .lowContrast:
|
||||
if surfaceType == .colorFill {
|
||||
return floating ? LowContrastColorFillFloatingConfiguration() : LowContrastColorFillConfiguration()
|
||||
} else {
|
||||
return floating ? LowContrastMediaFloatingConfiguration() : LowContrastMediaConfiguration()
|
||||
}
|
||||
|
||||
case .highContrast:
|
||||
return floating ? HighContrastFloatingConfiguration() : HighContrastConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
private var standardIconColorConfig: AnyColorable = {
|
||||
return 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)
|
||||
}.eraseToAnyColorable()
|
||||
}()
|
||||
|
||||
private var highContrastIconColorConfig: AnyColorable = {
|
||||
return SurfaceColorConfiguration(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight).eraseToAnyColorable()
|
||||
}()
|
||||
|
||||
private var selectedIconColorConfig: AnyColorable = {
|
||||
return ControlColorConfiguration().with {
|
||||
$0.setSurfaceColors(VDSColor.elementsBrandhighlight, VDSColor.elementsPrimaryOndark, forState: .normal)
|
||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||
}.eraseToAnyColorable()
|
||||
}()
|
||||
|
||||
private struct GhostConfiguration: Configuration {
|
||||
var kind: Kind = .ghost
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
var floating: Bool = false
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(.clear, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
}
|
||||
|
||||
private struct LowContrastColorFillConfiguration: Configuration {
|
||||
var kind: Kind = .lowContrast
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
var floating: Bool = false
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.paletteGray44.withAlphaComponent(0.06), VDSColor.paletteGray44.withAlphaComponent(0.26)).eraseToAnyColorable()
|
||||
}()
|
||||
}
|
||||
|
||||
private struct LowContrastColorFillFloatingConfiguration: Configuration {
|
||||
var kind: Kind = .lowContrast
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
var floating: Bool = true
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
}
|
||||
|
||||
private struct LowContrastMediaConfiguration: Configuration, Borderable {
|
||||
var kind: Kind = .lowContrast
|
||||
var surfaceType: SurfaceType = .media
|
||||
var floating: Bool = false
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
var borderWidth: CGFloat = 1.0
|
||||
var borderColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
}
|
||||
|
||||
private struct LowContrastMediaFloatingConfiguration: Configuration, Dropshadowable {
|
||||
var kind: Kind = .lowContrast
|
||||
var surfaceType: SurfaceType = .media
|
||||
var floating: Bool = true
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
var shadowColorConfig: AnyColorable = {
|
||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
||||
}()
|
||||
var shadowOpacity: CGFloat = 0.5
|
||||
var shadowOffset: CGSize = .init(width: 1, height: 1)
|
||||
var shadowRadius: CGFloat = 2
|
||||
}
|
||||
|
||||
private struct HighContrastConfiguration: Configuration {
|
||||
var kind: Kind = .highContrast
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
var floating: Bool = false
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
return ControlColorConfiguration().with {
|
||||
$0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal)
|
||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||
}.eraseToAnyColorable()
|
||||
|
||||
}()
|
||||
}
|
||||
|
||||
private struct HighContrastFloatingConfiguration: Configuration {
|
||||
var kind: Kind = .highContrast
|
||||
var surfaceType: SurfaceType = .colorFill
|
||||
var floating: Bool = true
|
||||
var backgroundColorConfig: AnyColorable = {
|
||||
return ControlColorConfiguration().with {
|
||||
$0.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forState: .normal)
|
||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||
}.eraseToAnyColorable()
|
||||
}()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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()
|
||||
|
||||
//create a layoutGuide for the icon to key off of
|
||||
let iconLayoutGuide = UILayoutGuide()
|
||||
addLayoutGuide(iconLayoutGuide)
|
||||
|
||||
//add the icon
|
||||
addSubview(icon)
|
||||
|
||||
//determines the height/width of the icon
|
||||
layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize)
|
||||
layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize)
|
||||
|
||||
//determines the center point of the icon
|
||||
centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0)
|
||||
centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0)
|
||||
|
||||
//activate the constraints
|
||||
NSLayoutConstraint.activate([layoutGuideWidthConstraint!,
|
||||
layoutGuideHeightConstraint!,
|
||||
centerXConstraint!,
|
||||
centerYConstraint!,
|
||||
iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor),
|
||||
iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
shouldUpdateView = false
|
||||
kind = .ghost
|
||||
surfaceType = .colorFill
|
||||
size = .large
|
||||
floating = false
|
||||
hideBorder = true
|
||||
iconOffset = .init(x: 0, y: 0)
|
||||
iconName = nil
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
//ensure there is an icon to set
|
||||
if let currentIconName {
|
||||
icon.name = currentIconName
|
||||
let color = iconColorConfig.getColor(self)
|
||||
icon.color = color
|
||||
icon.size = size.value
|
||||
icon.customSize = customSize
|
||||
} else {
|
||||
icon.reset()
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
let currentConfig = currentConfiguration
|
||||
|
||||
backgroundColor = currentConfig.backgroundColorConfig.getColor(self)
|
||||
|
||||
// calculate center point for child view with offset
|
||||
let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y)
|
||||
centerXConstraint?.constant = childCenter.x - center.x
|
||||
centerYConstraint?.constant = childCenter.y - center.y
|
||||
|
||||
//updating current container size
|
||||
var iconLayoutSize = size.containerSize
|
||||
if let customSize {
|
||||
iconLayoutSize = CGFloat(customSize)
|
||||
}
|
||||
// check to see if this is fitToIcon
|
||||
if fitToIcon && kind == .ghost {
|
||||
iconLayoutSize = size.value.dimensions.width
|
||||
layer.cornerRadius = 0
|
||||
} else {
|
||||
layer.cornerRadius = min(frame.width, frame.height) / 2.0
|
||||
}
|
||||
|
||||
layoutGuideWidthConstraint?.constant = iconLayoutSize
|
||||
layoutGuideHeightConstraint?.constant = iconLayoutSize
|
||||
|
||||
//border
|
||||
if let borderable = currentConfig as? Borderable {
|
||||
layer.borderColor = borderable.borderColorConfig.getColor(self).cgColor
|
||||
layer.borderWidth = borderable.borderWidth
|
||||
icon.layer.borderWidth = borderable.borderWidth
|
||||
} else {
|
||||
layer.borderColor = nil
|
||||
layer.borderWidth = 0
|
||||
icon.layer.borderWidth = 0
|
||||
}
|
||||
|
||||
if let dropshadowable = currentConfig as? Dropshadowable {
|
||||
layer.masksToBounds = false
|
||||
layer.shadowColor = dropshadowable.shadowColorConfig.getColor(self).cgColor
|
||||
layer.shadowOpacity = Float(dropshadowable.shadowOpacity)
|
||||
layer.shadowOffset = dropshadowable.shadowOffset
|
||||
layer.shadowRadius = dropshadowable.shadowRadius
|
||||
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
|
||||
layer.shouldRasterize = true
|
||||
layer.rasterizationScale = UIScreen.main.scale
|
||||
} else {
|
||||
layer.shadowOpacity = 0
|
||||
layer.shadowRadius = 0
|
||||
layer.shadowPath = nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: AppleGuidlinesTouchable
|
||||
extension ButtonIcon: AppleGuidlinesTouchable {
|
||||
|
||||
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
}
|
||||
|
||||
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let view = super.hitTest(point, with: event)
|
||||
|
||||
if view == icon {
|
||||
return self
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private protocol Borderable {
|
||||
var borderWidth: CGFloat { get set }
|
||||
var borderColorConfig: AnyColorable { get set }
|
||||
}
|
||||
|
||||
private protocol Dropshadowable {
|
||||
var shadowColorConfig: AnyColorable { get set }
|
||||
var shadowOpacity: CGFloat { get set }
|
||||
var shadowOffset: CGSize { get set }
|
||||
var shadowRadius: CGFloat { get set }
|
||||
}
|
||||
|
||||
private protocol Configuration {
|
||||
var kind: ButtonIcon.Kind { get set }
|
||||
var surfaceType: ButtonIcon.SurfaceType { get set }
|
||||
var floating: Bool { get set }
|
||||
var backgroundColorConfig: AnyColorable { get set }
|
||||
}
|
||||
@ -28,7 +28,14 @@ open class Icon: View {
|
||||
$0.clipsToBounds = true
|
||||
}
|
||||
|
||||
open var color: Color = .black { didSet { setNeedsUpdate() }}
|
||||
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")
|
||||
}
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
open var size: Size = .medium { didSet { setNeedsUpdate() }}
|
||||
open var name: Name? { didSet { setNeedsUpdate() }}
|
||||
open var customSize: Int? { didSet { setNeedsUpdate() }}
|
||||
@ -57,7 +64,7 @@ open class Icon: View {
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
color = .black
|
||||
color = VDSColor.paletteBlack
|
||||
imageView.image = nil
|
||||
}
|
||||
|
||||
@ -67,12 +74,12 @@ open class Icon: View {
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
//get the color for the image
|
||||
var imageColor = color.value
|
||||
var imageColor = color
|
||||
|
||||
//ensure the correct color for white/black colors
|
||||
if surface == .dark && color == Color.black {
|
||||
if surface == .dark && color == VDSColor.paletteBlack {
|
||||
imageColor = VDSColor.elementsPrimaryOndark
|
||||
} else if surface == .light && color == Color.black {
|
||||
} else if surface == .light && color == VDSColor.paletteBlack {
|
||||
imageColor = VDSColor.elementsPrimaryOnlight
|
||||
}
|
||||
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
//
|
||||
// IconColor.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 1/9/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
import UIKit
|
||||
|
||||
extension Icon {
|
||||
public enum Color: String, CaseIterable {
|
||||
case black
|
||||
case white
|
||||
case red
|
||||
case gray95
|
||||
case gray85
|
||||
case gray65
|
||||
case gray44
|
||||
case gray20
|
||||
case gray11
|
||||
case orange94
|
||||
case orange83
|
||||
case orange71
|
||||
case orange58
|
||||
case orange41
|
||||
case orange24
|
||||
case orange17
|
||||
case yellow94
|
||||
case yellow87
|
||||
case yellow74
|
||||
case yellow53
|
||||
case yellow39
|
||||
case yellow20
|
||||
case yellow15
|
||||
case blue94
|
||||
case blue82
|
||||
case blue62
|
||||
case blue46
|
||||
case blue38
|
||||
case blue21
|
||||
case blue15
|
||||
case green91
|
||||
case green77
|
||||
case green61
|
||||
case green36
|
||||
case green26
|
||||
case green15
|
||||
case green10
|
||||
case pink87
|
||||
case pink76
|
||||
case pink62
|
||||
case pink46
|
||||
case pink25
|
||||
case purple85
|
||||
case purple75
|
||||
case purple60
|
||||
case purple39
|
||||
case purple20
|
||||
|
||||
// Map each color name to its corresponding UIColor object.
|
||||
public var value: UIColor {
|
||||
switch self {
|
||||
case .black: return VDSColor.paletteBlack
|
||||
case .white: return VDSColor.paletteWhite
|
||||
case .red: return VDSColor.paletteRed
|
||||
case .gray95: return VDSColor.paletteGray95
|
||||
case .gray85: return VDSColor.paletteGray85
|
||||
case .gray65: return VDSColor.paletteGray65
|
||||
case .gray44: return VDSColor.paletteGray44
|
||||
case .gray20: return VDSColor.paletteGray20
|
||||
case .gray11: return VDSColor.paletteGray11
|
||||
case .orange94: return VDSColor.paletteOrange94
|
||||
case .orange83: return VDSColor.paletteOrange83
|
||||
case .orange71: return VDSColor.paletteOrange71
|
||||
case .orange58: return VDSColor.paletteOrange58
|
||||
case .orange41: return VDSColor.paletteOrange41
|
||||
case .orange24: return VDSColor.paletteOrange24
|
||||
case .orange17: return VDSColor.paletteOrange17
|
||||
case .yellow94: return VDSColor.paletteYellow94
|
||||
case .yellow87: return VDSColor.paletteYellow87
|
||||
case .yellow74: return VDSColor.paletteYellow74
|
||||
case .yellow53: return VDSColor.paletteYellow53
|
||||
case .yellow39: return VDSColor.paletteYellow39
|
||||
case .yellow20: return VDSColor.paletteYellow20
|
||||
case .yellow15: return VDSColor.paletteYellow15
|
||||
case .blue94: return VDSColor.paletteBlue94
|
||||
case .blue82: return VDSColor.paletteBlue82
|
||||
case .blue62: return VDSColor.paletteBlue62
|
||||
case .blue46: return VDSColor.paletteBlue46
|
||||
case .blue38: return VDSColor.paletteBlue38
|
||||
case .blue21: return VDSColor.paletteBlue21
|
||||
case .blue15: return VDSColor.paletteBlue15
|
||||
case .green91: return VDSColor.paletteGreen91
|
||||
case .green77: return VDSColor.paletteGreen77
|
||||
case .green61: return VDSColor.paletteGreen61
|
||||
case .green36: return VDSColor.paletteGreen36
|
||||
case .green26: return VDSColor.paletteGreen26
|
||||
case .green15: return VDSColor.paletteGreen15
|
||||
case .green10: return VDSColor.paletteGreen10
|
||||
case .pink87: return VDSColor.palettePink87
|
||||
case .pink76: return VDSColor.palettePink76
|
||||
case .pink62: return VDSColor.palettePink62
|
||||
case .pink46: return VDSColor.palettePink46
|
||||
case .pink25: return VDSColor.palettePink25
|
||||
case .purple85: return VDSColor.palettePurple85
|
||||
case .purple75: return VDSColor.palettePurple75
|
||||
case .purple60: return VDSColor.palettePurple60
|
||||
case .purple39: return VDSColor.palettePurple39
|
||||
case .purple20: return VDSColor.palettePurple20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -274,7 +274,7 @@ open class Notification: View {
|
||||
}
|
||||
|
||||
private func updateIcons() {
|
||||
let iconColor = surface == .dark ? Icon.Color.white : Icon.Color.black
|
||||
let iconColor = surface == .dark ? VDSColor.paletteWhite : VDSColor.paletteBlack
|
||||
typeIcon.name = type.styleIconName()
|
||||
typeIcon.color = iconColor
|
||||
closeButton.color = iconColor
|
||||
|
||||
@ -311,7 +311,7 @@ open class EntryField: Control, Changeable {
|
||||
errorLabel.disabled = disabled
|
||||
errorLabel.isHidden = false
|
||||
icon.name = .error
|
||||
icon.color = .black
|
||||
icon.color = VDSColor.paletteBlack
|
||||
icon.surface = surface
|
||||
icon.isHidden = disabled
|
||||
} else {
|
||||
|
||||
@ -177,7 +177,7 @@ open class InputField: EntryField, UITextFieldDelegate {
|
||||
successLabel.isHidden = false
|
||||
errorLabel.isHidden = true
|
||||
icon.name = .checkmarkAlt
|
||||
icon.color = .black
|
||||
icon.color = VDSColor.paletteBlack
|
||||
icon.surface = surface
|
||||
icon.isHidden = disabled
|
||||
} else {
|
||||
|
||||
@ -121,11 +121,7 @@ extension UIView {
|
||||
extension UIView {
|
||||
|
||||
internal func removeDebugBorder() {
|
||||
layer.sublayers?.forEach({ layer in
|
||||
if layer.name?.hasPrefix("debug") ?? false {
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
})
|
||||
layer.remove(layerName: "debug")
|
||||
}
|
||||
|
||||
internal func addDebugBorder(color: UIColor = .red) {
|
||||
@ -177,3 +173,13 @@ extension UIView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CALayer {
|
||||
func remove(layerName: String) {
|
||||
sublayers?.forEach({ layer in
|
||||
if layer.name?.hasPrefix(layerName) ?? false {
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
119
VDS/Extensions/VDSColor.swift
Normal file
119
VDS/Extensions/VDSColor.swift
Normal file
@ -0,0 +1,119 @@
|
||||
//
|
||||
// VDSColor.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 5/15/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
|
||||
extension VDSColor {
|
||||
public enum Color: String, CaseIterable {
|
||||
case paletteBlack
|
||||
case paletteWhite
|
||||
case paletteRed
|
||||
case paletteGray95
|
||||
case paletteGray85
|
||||
case paletteGray65
|
||||
case paletteGray44
|
||||
case paletteGray20
|
||||
case paletteGray11
|
||||
case paletteOrange94
|
||||
case paletteOrange83
|
||||
case paletteOrange71
|
||||
case paletteOrange58
|
||||
case paletteOrange41
|
||||
case paletteOrange24
|
||||
case paletteOrange17
|
||||
case paletteYellow94
|
||||
case paletteYellow87
|
||||
case paletteYellow74
|
||||
case paletteYellow53
|
||||
case paletteYellow39
|
||||
case paletteYellow20
|
||||
case paletteYellow15
|
||||
case paletteBlue94
|
||||
case paletteBlue82
|
||||
case paletteBlue62
|
||||
case paletteBlue46
|
||||
case paletteBlue38
|
||||
case paletteBlue21
|
||||
case paletteBlue15
|
||||
case paletteGreen91
|
||||
case paletteGreen77
|
||||
case paletteGreen61
|
||||
case paletteGreen36
|
||||
case paletteGreen26
|
||||
case paletteGreen15
|
||||
case paletteGreen10
|
||||
case palettePink87
|
||||
case palettePink76
|
||||
case palettePink62
|
||||
case palettePink46
|
||||
case palettePink25
|
||||
case palettePurple85
|
||||
case palettePurple75
|
||||
case palettePurple60
|
||||
case palettePurple39
|
||||
case palettePurple20
|
||||
case backgroundPrimaryLight
|
||||
case backgroundPrimaryDark
|
||||
case backgroundSecondaryLight
|
||||
case backgroundSecondaryDark
|
||||
case backgroundBrandhighlight
|
||||
case feedbackErrorOnlight
|
||||
case feedbackErrorOndark
|
||||
case feedbackErrorBackgroundOnlight
|
||||
case feedbackErrorBackgroundOndark
|
||||
case feedbackWarningOnlight
|
||||
case feedbackWarningOndark
|
||||
case feedbackWarningBackgroundOnlight
|
||||
case feedbackWarningBackgroundOndark
|
||||
case feedbackInformationOnlight
|
||||
case feedbackInformationOndark
|
||||
case feedbackInformationBackgroundOnlight
|
||||
case feedbackInformationBackgroundOndark
|
||||
case feedbackSuccessOnlight
|
||||
case feedbackSuccessOndark
|
||||
case feedbackSuccessBackgroundOnlight
|
||||
case feedbackSuccessBackgroundOndark
|
||||
case interactiveActiveOnlight
|
||||
case interactiveActiveOndark
|
||||
case interactiveDisabledOnlight
|
||||
case interactiveDisabledOndark
|
||||
case interactiveScrollthumbOnlight
|
||||
case interactiveScrollthumbOndark
|
||||
case interactiveScrollthumbHoverOnlight
|
||||
case interactiveScrollthumbHoverOndark
|
||||
case interactiveScrolltrackOnlight
|
||||
case interactiveScrolltrackOndark
|
||||
case elementsPrimaryOnlight
|
||||
case elementsPrimaryOndark
|
||||
case elementsSecondaryOnlight
|
||||
case elementsSecondaryOndark
|
||||
case elementsBrandhighlight
|
||||
case elementsLowcontrastOnlight
|
||||
case elementsLowcontrastOndark
|
||||
|
||||
// Map each color name to its corresponding UIColor object.
|
||||
public var uiColor: UIColor {
|
||||
do {
|
||||
let color = try VDSColor.getTokenByString(tokenName: "VDSColor.\(rawValue)")
|
||||
return color
|
||||
} catch {
|
||||
print(error)
|
||||
return VDSColor.paletteBlack
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIColor {
|
||||
public static func isVDSColor(color: UIColor) -> Bool {
|
||||
guard let hex = color.hexString else { return false }
|
||||
let found = VDSColor.Color.allCases.first{ $0.uiColor.hexString == hex }
|
||||
guard let _ = found else { return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user