Merge branch 'feature/buttonIcon' into 'develop'
VDS Components - VDS Brand 3.0 Button Icon for IOS See merge request BPHV_MIPS/vds_ios!147
This commit is contained in:
commit
a317125072
@ -7,6 +7,8 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; };
|
||||||
|
18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; };
|
||||||
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
||||||
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; };
|
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; };
|
||||||
44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; };
|
44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; };
|
||||||
@ -169,6 +171,8 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
|
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; };
|
||||||
445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||||
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = "<group>"; };
|
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = "<group>"; };
|
||||||
44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||||
@ -674,6 +678,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */,
|
EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */,
|
||||||
|
18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */,
|
||||||
|
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */,
|
||||||
);
|
);
|
||||||
path = ButtonIcon;
|
path = ButtonIcon;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -942,6 +948,7 @@
|
|||||||
EAEEECAF2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt in Resources */,
|
EAEEECAF2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt in Resources */,
|
||||||
EAEEEC922B1F807300531FC2 /* BadgeChangeLog.txt in Resources */,
|
EAEEEC922B1F807300531FC2 /* BadgeChangeLog.txt in Resources */,
|
||||||
EAEEEC9E2B1F8F7700531FC2 /* ButtonGroupChangeLog.txt in Resources */,
|
EAEEEC9E2B1F8F7700531FC2 /* ButtonGroupChangeLog.txt in Resources */,
|
||||||
|
18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */,
|
||||||
EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */,
|
EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */,
|
||||||
EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */,
|
EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */,
|
||||||
EAEEECA02B1F908200531FC2 /* BadgeIndicatorChangeLog.txt in Resources */,
|
EAEEECA02B1F908200531FC2 /* BadgeIndicatorChangeLog.txt in Resources */,
|
||||||
@ -1064,6 +1071,7 @@
|
|||||||
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
|
||||||
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */,
|
||||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
|
||||||
|
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */,
|
||||||
EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */,
|
EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */,
|
||||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
|
||||||
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
|
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
|
||||||
|
|||||||
@ -8,12 +8,13 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
import VDSColorTokens
|
import VDSColorTokens
|
||||||
|
import Combine
|
||||||
|
|
||||||
/// A button icon is an interactive element that visually communicates the action it triggers via an icon.
|
/// A button icon is an interactive element that visually communicates the action it triggers via an icon.
|
||||||
/// It usually represents a supplementary or utilitarian action. A button icon can stand alone, but often
|
/// It usually represents a supplementary or utilitarian action. A button icon can stand alone, but often
|
||||||
/// exists in a group when there are several actions that can be performed.
|
/// exists in a group when there are several actions that can be performed.
|
||||||
@objc(VDSButtonIcon)
|
@objc(VDSButtonIcon)
|
||||||
open class ButtonIcon: Control {
|
open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
@ -67,17 +68,45 @@ open class ButtonIcon: Control {
|
|||||||
private var centerYConstraint: NSLayoutConstraint?
|
private var centerYConstraint: NSLayoutConstraint?
|
||||||
private var layoutGuideWidthConstraint: NSLayoutConstraint?
|
private var layoutGuideWidthConstraint: NSLayoutConstraint?
|
||||||
private var layoutGuideHeightConstraint: NSLayoutConstraint?
|
private var layoutGuideHeightConstraint: NSLayoutConstraint?
|
||||||
|
private var badgeIndicatorLeadingConstraint: NSLayoutConstraint?
|
||||||
|
private var badgeIndicatorTrailingConstraint: NSLayoutConstraint?
|
||||||
|
private var badgeIndicatorCenterXConstraint: NSLayoutConstraint?
|
||||||
|
private var badgeIndicatorCenterYConstraint: NSLayoutConstraint?
|
||||||
private var currentIconName: Icon.Name? {
|
private var currentIconName: Icon.Name? {
|
||||||
if let selectedIconName {
|
if let selectedIconName, isSelected {
|
||||||
return selectedIconName
|
return selectedIconName
|
||||||
} else {
|
} else {
|
||||||
return iconName
|
return iconName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var badgeIndicatorOffset: CGPoint {
|
||||||
|
switch (size, kind) {
|
||||||
|
case (.small, .ghost):
|
||||||
|
return .init(x: 1, y: 0)
|
||||||
|
case (.large, .ghost):
|
||||||
|
return .init(x: 1, y: 1)
|
||||||
|
case (.small, .lowContrast), (.small, .highContrast):
|
||||||
|
return .init(x: 4, y: 4)
|
||||||
|
case (.large, .lowContrast), (.large, .highContrast):
|
||||||
|
return .init(x: 6, y: 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Public Properties
|
// MARK: - Public Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
///Badge Indicator object used to render for the ButtonIcon.
|
||||||
|
open var badgeIndicator = BadgeIndicator().with {
|
||||||
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
$0.size = .small
|
||||||
|
$0.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If set, this is used to render the badge indicator.
|
||||||
|
open var badgeIndicatorModel: BadgeIndicatorModel? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
/// Icon object used to render out the Icon for this ButtonIcon.
|
/// Icon object used to render out the Icon for this ButtonIcon.
|
||||||
open var icon = Icon().with { $0.isUserInteractionEnabled = false }
|
open var icon = Icon().with { $0.isUserInteractionEnabled = false }
|
||||||
|
|
||||||
@ -108,21 +137,39 @@ open class ButtonIcon: Control {
|
|||||||
/// If set to true, the button icon will not have a border.
|
/// If set to true, the button icon will not have a border.
|
||||||
open var hideBorder: Bool = true { didSet { setNeedsUpdate() } }
|
open var hideBorder: Bool = true { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// If provided, the badge indicator will present.
|
||||||
|
open var showBadgeIndicator: Bool = false { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// If true, button will be rendered as selected, when it is selectable.
|
||||||
|
open var selectable: Bool = false {
|
||||||
|
didSet {
|
||||||
|
//unselect
|
||||||
|
if !selectable && isSelected {
|
||||||
|
isSelected = false
|
||||||
|
}
|
||||||
|
setNeedsUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Used to move the icon inside the button in both x and y axis.
|
/// Used to move the icon inside the button in both x and y axis.
|
||||||
open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } }
|
open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
open var onChangeSubscriber: AnyCancellable?
|
||||||
|
|
||||||
|
open var inputId: String? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
open var value: AnyHashable? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Configuration
|
// MARK: - Configuration
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private var iconColorConfiguration: AnyColorable {
|
private var iconColorConfiguration: AnyColorable {
|
||||||
if selectedIconName != nil {
|
if kind == .highContrast {
|
||||||
return selectedIconColorConfiguration
|
return highContrastIconColorConfiguration
|
||||||
|
} else if kind == .lowContrast {
|
||||||
|
return (surfaceType == .colorFill) ? lowContrastIconColorConfiguration : (floating ? lowContrastIconColorConfiguration : standardIconColorConfiguration)
|
||||||
} else {
|
} else {
|
||||||
if kind == .highContrast {
|
return standardIconColorConfiguration
|
||||||
return highContrastIconColorConfiguration
|
|
||||||
} else {
|
|
||||||
return standardIconColorConfiguration
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +194,19 @@ open class ButtonIcon: Control {
|
|||||||
return ControlColorConfiguration().with {
|
return ControlColorConfiguration().with {
|
||||||
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal)
|
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||||
|
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected)
|
||||||
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
|
||||||
|
}.eraseToAnyColorable()
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var lowContrastIconColorConfiguration: 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.paletteBlack.withAlphaComponent(0.70), forState: .disabled)
|
||||||
|
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected)
|
||||||
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.paletteBlack.withAlphaComponent(0.70), forState: [.selected, .disabled])
|
||||||
}.eraseToAnyColorable()
|
}.eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -155,14 +214,6 @@ open class ButtonIcon: Control {
|
|||||||
return SurfaceColorConfiguration(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight).eraseToAnyColorable()
|
return SurfaceColorConfiguration(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private var selectedIconColorConfiguration: 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 {
|
private struct GhostConfiguration: Configuration {
|
||||||
var kind: Kind = .ghost
|
var kind: Kind = .ghost
|
||||||
var surfaceType: SurfaceType = .colorFill
|
var surfaceType: SurfaceType = .colorFill
|
||||||
@ -181,13 +232,19 @@ open class ButtonIcon: Control {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct LowContrastColorFillFloatingConfiguration: Configuration {
|
private struct LowContrastColorFillFloatingConfiguration: Configuration, Dropshadowable {
|
||||||
var kind: Kind = .lowContrast
|
var kind: Kind = .lowContrast
|
||||||
var surfaceType: SurfaceType = .colorFill
|
var surfaceType: SurfaceType = .colorFill
|
||||||
var floating: Bool = true
|
var floating: Bool = true
|
||||||
var backgroundColorConfiguration: AnyColorable = {
|
var backgroundColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
|
var shadowColorConfiguration: AnyColorable = {
|
||||||
|
SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable()
|
||||||
|
}()
|
||||||
|
var shadowOpacity: CGFloat = 0.16
|
||||||
|
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
||||||
|
var shadowRadius: CGFloat = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct LowContrastMediaConfiguration: Configuration, Borderable {
|
private struct LowContrastMediaConfiguration: Configuration, Borderable {
|
||||||
@ -195,11 +252,11 @@ open class ButtonIcon: Control {
|
|||||||
var surfaceType: SurfaceType = .media
|
var surfaceType: SurfaceType = .media
|
||||||
var floating: Bool = false
|
var floating: Bool = false
|
||||||
var backgroundColorConfiguration: AnyColorable = {
|
var backgroundColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
var borderWidth: CGFloat = 1.0
|
var borderWidth: CGFloat = 1.0
|
||||||
var borderColorConfiguration: AnyColorable = {
|
var borderColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,14 +265,14 @@ open class ButtonIcon: Control {
|
|||||||
var surfaceType: SurfaceType = .media
|
var surfaceType: SurfaceType = .media
|
||||||
var floating: Bool = true
|
var floating: Bool = true
|
||||||
var backgroundColorConfiguration: AnyColorable = {
|
var backgroundColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
var shadowColorConfiguration: AnyColorable = {
|
var shadowColorConfiguration: AnyColorable = {
|
||||||
SurfaceColorConfiguration(VDSColor.paletteBlack, .clear).eraseToAnyColorable()
|
SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
var shadowOpacity: CGFloat = 0.16
|
var shadowOpacity: CGFloat = 0.16
|
||||||
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
||||||
var shadowRadius: CGFloat = 2
|
var shadowRadius: CGFloat = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct HighContrastConfiguration: Configuration {
|
private struct HighContrastConfiguration: Configuration {
|
||||||
@ -225,32 +282,48 @@ open class ButtonIcon: Control {
|
|||||||
var backgroundColorConfiguration: AnyColorable = {
|
var backgroundColorConfiguration: AnyColorable = {
|
||||||
return ControlColorConfiguration().with {
|
return ControlColorConfiguration().with {
|
||||||
$0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal)
|
$0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal)
|
||||||
|
$0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .selected)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||||
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
|
||||||
}.eraseToAnyColorable()
|
}.eraseToAnyColorable()
|
||||||
|
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct HighContrastFloatingConfiguration: Configuration {
|
private struct HighContrastFloatingConfiguration: Configuration, Dropshadowable {
|
||||||
var kind: Kind = .highContrast
|
var kind: Kind = .highContrast
|
||||||
var surfaceType: SurfaceType = .colorFill
|
var surfaceType: SurfaceType = .colorFill
|
||||||
var floating: Bool = true
|
var floating: Bool = true
|
||||||
var backgroundColorConfiguration: AnyColorable = {
|
var backgroundColorConfiguration: AnyColorable = {
|
||||||
return ControlColorConfiguration().with {
|
return ControlColorConfiguration().with {
|
||||||
$0.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forState: .normal)
|
$0.setSurfaceColors(VDSColor.paletteGray20, VDSColor.paletteWhite, forState: .normal)
|
||||||
|
$0.setSurfaceColors(VDSColor.paletteGray20, VDSColor.paletteWhite, forState: .selected)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
|
||||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||||
|
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: [.selected, .highlighted])
|
||||||
|
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
|
||||||
}.eraseToAnyColorable()
|
}.eraseToAnyColorable()
|
||||||
}()
|
}()
|
||||||
|
var shadowColorConfiguration: AnyColorable = {
|
||||||
|
SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable()
|
||||||
|
}()
|
||||||
|
var shadowOpacity: CGFloat = 0.16
|
||||||
|
var shadowOffset: CGSize = .init(width: 0, height: 2)
|
||||||
|
var shadowRadius: CGFloat = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var badgeIndicatorDefaultSize: CGSize = .zero
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
||||||
open override func setup() {
|
open override func setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityTraits = .image
|
||||||
|
accessibilityElements = [badgeIndicator]
|
||||||
|
|
||||||
//create a layoutGuide for the icon to key off of
|
//create a layoutGuide for the icon to key off of
|
||||||
let iconLayoutGuide = UILayoutGuide()
|
let iconLayoutGuide = UILayoutGuide()
|
||||||
@ -259,10 +332,21 @@ open class ButtonIcon: Control {
|
|||||||
//add the icon
|
//add the icon
|
||||||
addSubview(icon)
|
addSubview(icon)
|
||||||
|
|
||||||
|
//add badgeIndicator
|
||||||
|
addSubview(badgeIndicator)
|
||||||
|
badgeIndicator.isHidden = !showBadgeIndicator
|
||||||
|
badgeIndicatorDefaultSize = badgeIndicator.frame.size
|
||||||
|
|
||||||
//determines the height/width of the icon
|
//determines the height/width of the icon
|
||||||
layoutGuideWidthConstraint = iconLayoutGuide.width(constant: size.containerSize)
|
layoutGuideWidthConstraint = iconLayoutGuide.width(constant: size.containerSize)
|
||||||
layoutGuideHeightConstraint = iconLayoutGuide.height(constant: size.containerSize)
|
layoutGuideHeightConstraint = iconLayoutGuide.height(constant: size.containerSize)
|
||||||
|
badgeIndicatorLeadingConstraint = badgeIndicator.leadingAnchor.constraint(equalTo: icon.centerXAnchor)
|
||||||
|
badgeIndicatorTrailingConstraint = badgeIndicator.trailingAnchor.constraint(equalTo: icon.centerXAnchor)
|
||||||
|
badgeIndicatorCenterXConstraint = badgeIndicator.centerXAnchor.constraint(equalTo: icon.centerXAnchor)
|
||||||
|
badgeIndicatorCenterYConstraint = icon.centerYAnchor.constraint(equalTo: badgeIndicator.centerYAnchor)
|
||||||
|
badgeIndicatorCenterYConstraint?.isActive = true
|
||||||
|
|
||||||
|
badgeIndicatorLeadingConstraint?.isActive = true
|
||||||
//pin layout guide
|
//pin layout guide
|
||||||
iconLayoutGuide
|
iconLayoutGuide
|
||||||
.pinTop()
|
.pinTop()
|
||||||
@ -277,6 +361,24 @@ open class ButtonIcon: Control {
|
|||||||
centerYConstraint?.activate()
|
centerYConstraint?.activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executed on initialization for this View.
|
||||||
|
open override func initialSetup() {
|
||||||
|
super.initialSetup()
|
||||||
|
onClick = { control in
|
||||||
|
guard control.isEnabled else { return }
|
||||||
|
if control.selectedIconName != nil && control.selectable {
|
||||||
|
control.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This will change the state of the Selector and execute the actionBlock if provided.
|
||||||
|
open func toggle() {
|
||||||
|
//removed error
|
||||||
|
isSelected.toggle()
|
||||||
|
sendActions(for: .valueChanged)
|
||||||
|
}
|
||||||
|
|
||||||
/// Resets to default settings.
|
/// Resets to default settings.
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
@ -288,6 +390,10 @@ open class ButtonIcon: Control {
|
|||||||
hideBorder = true
|
hideBorder = true
|
||||||
iconOffset = .init(x: 0, y: 0)
|
iconOffset = .init(x: 0, y: 0)
|
||||||
iconName = nil
|
iconName = nil
|
||||||
|
selectedIconName = nil
|
||||||
|
showBadgeIndicator = false
|
||||||
|
selectable = false
|
||||||
|
badgeIndicatorModel = nil
|
||||||
shouldUpdateView = true
|
shouldUpdateView = true
|
||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
@ -306,6 +412,7 @@ open class ButtonIcon: Control {
|
|||||||
} else {
|
} else {
|
||||||
icon.reset()
|
icon.reset()
|
||||||
}
|
}
|
||||||
|
updateBadgeIndicator()
|
||||||
setNeedsLayout()
|
setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +445,7 @@ open class ButtonIcon: Control {
|
|||||||
layoutGuideHeightConstraint?.constant = iconLayoutSize
|
layoutGuideHeightConstraint?.constant = iconLayoutSize
|
||||||
|
|
||||||
//border
|
//border
|
||||||
if let borderable = currentConfig as? Borderable {
|
if let borderable = currentConfig as? Borderable, hideBorder {
|
||||||
layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor
|
layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor
|
||||||
layer.borderWidth = borderable.borderWidth
|
layer.borderWidth = borderable.borderWidth
|
||||||
} else {
|
} else {
|
||||||
@ -352,6 +459,66 @@ open class ButtonIcon: Control {
|
|||||||
removeDropShadow()
|
removeDropShadow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
badgeIndicatorCenterXConstraint?.constant = badgeIndicatorOffset.x + badgeIndicatorDefaultSize.width/2
|
||||||
|
badgeIndicatorCenterYConstraint?.constant = badgeIndicatorOffset.y + badgeIndicatorDefaultSize.height/2
|
||||||
|
badgeIndicatorLeadingConstraint?.constant = badgeIndicatorOffset.x
|
||||||
|
badgeIndicatorTrailingConstraint?.constant = badgeIndicatorOffset.x + badgeIndicatorDefaultSize.width
|
||||||
|
|
||||||
|
if showBadgeIndicator {
|
||||||
|
updateExpandDirectionalConstraints()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
private func updateBadgeIndicator() {
|
||||||
|
badgeIndicator.isHidden = !showBadgeIndicator
|
||||||
|
|
||||||
|
guard let badgeIndicatorModel else {
|
||||||
|
badgeIndicator.isHidden = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
badgeIndicator.surface = surface
|
||||||
|
badgeIndicator.kind = badgeIndicatorModel.kind
|
||||||
|
badgeIndicator.fillColor = badgeIndicatorModel.fillColor
|
||||||
|
badgeIndicator.size = badgeIndicatorModel.size
|
||||||
|
badgeIndicator.maximumDigits = badgeIndicatorModel.maximumDigits
|
||||||
|
badgeIndicator.width = badgeIndicatorModel.width
|
||||||
|
badgeIndicator.height = badgeIndicatorModel.height
|
||||||
|
badgeIndicator.number = badgeIndicatorModel.number
|
||||||
|
badgeIndicator.leadingCharacter = badgeIndicatorModel.leadingCharacter
|
||||||
|
badgeIndicator.trailingText = badgeIndicatorModel.trailingText
|
||||||
|
badgeIndicator.dotSize = badgeIndicatorModel.dotSize
|
||||||
|
badgeIndicator.verticalPadding = badgeIndicatorModel.verticalPadding
|
||||||
|
badgeIndicator.horizontalPadding = badgeIndicatorModel.horizontalPadding
|
||||||
|
badgeIndicator.hideDot = badgeIndicatorModel.hideDot
|
||||||
|
badgeIndicator.hideBorder = badgeIndicatorModel.hideBorder
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateExpandDirectionalConstraints() {
|
||||||
|
guard let badgeIndicatorModel else { return }
|
||||||
|
switch badgeIndicatorModel.expandDirection {
|
||||||
|
case .right:
|
||||||
|
badgeIndicatorLeadingConstraint?.isActive = true
|
||||||
|
badgeIndicatorTrailingConstraint?.isActive = false
|
||||||
|
badgeIndicatorCenterXConstraint?.isActive = false
|
||||||
|
case .center:
|
||||||
|
badgeIndicatorLeadingConstraint?.isActive = false
|
||||||
|
badgeIndicatorTrailingConstraint?.isActive = false
|
||||||
|
badgeIndicatorCenterXConstraint?.isActive = true
|
||||||
|
case .left:
|
||||||
|
badgeIndicatorLeadingConstraint?.isActive = false
|
||||||
|
badgeIndicatorCenterXConstraint?.isActive = false
|
||||||
|
badgeIndicatorTrailingConstraint?.isActive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to update any Accessibility properties.
|
||||||
|
open override func updateAccessibility() {
|
||||||
|
super.updateAccessibility()
|
||||||
|
setAccessibilityLabel(for: [icon, badgeIndicator.label])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// ButtonIconBadgeIndicatorModel.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Kanamarlapudi, Vasavi on 08/02/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension ButtonIcon {
|
||||||
|
|
||||||
|
//Model that represents the options available for the Badge Indicator
|
||||||
|
public struct BadgeIndicatorModel {
|
||||||
|
/// Enum used to describe the badge indicator direction of icon button determining the expand direction.
|
||||||
|
public enum ExpandDirection: String, CaseIterable {
|
||||||
|
case right, center, left
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies expand direction to Badge Indicator if shows badge indicator.
|
||||||
|
public var expandDirection: ExpandDirection = .right
|
||||||
|
|
||||||
|
/// Kind that will be used for the badge indicator.
|
||||||
|
public var kind: BadgeIndicator.Kind
|
||||||
|
|
||||||
|
/// Fill color that will be used for the badge indicator.
|
||||||
|
public var fillColor: BadgeIndicator.FillColor
|
||||||
|
|
||||||
|
/// Size that will be used for the badge indicator.
|
||||||
|
public var size: BadgeIndicator.Size
|
||||||
|
|
||||||
|
/// Number of digits that will be used for the badge indicator.
|
||||||
|
public var maximumDigits: BadgeIndicator.MaximumDigits
|
||||||
|
|
||||||
|
/// Max width that will be used for the badge indicator.
|
||||||
|
public var width: CGFloat?
|
||||||
|
|
||||||
|
/// Max height that will be used for the badge indicator.
|
||||||
|
public var height: CGFloat?
|
||||||
|
|
||||||
|
/// Number that will be used for the badge indicator.
|
||||||
|
public var number: Int?
|
||||||
|
|
||||||
|
/// Leading Character that will be used for the badge indicator.
|
||||||
|
public var leadingCharacter: String?
|
||||||
|
|
||||||
|
/// Trailing Text height that will be used for the badge indicator.
|
||||||
|
public var trailingText: String?
|
||||||
|
|
||||||
|
/// Dot Size that will be used for the badge indicator.
|
||||||
|
public var dotSize: CGFloat?
|
||||||
|
|
||||||
|
/// Vertical Padding that will be used for the badge indicator.
|
||||||
|
public var verticalPadding: CGFloat?
|
||||||
|
|
||||||
|
/// Horizontal Padding that will be used for the badge indicator.
|
||||||
|
public var horizontalPadding: CGFloat?
|
||||||
|
|
||||||
|
/// Hide Dot that will be used for the badge indicator.
|
||||||
|
public var hideDot: Bool = false
|
||||||
|
|
||||||
|
/// Hide Border that will be used for the badge indicator.
|
||||||
|
public var hideBorder: Bool = false
|
||||||
|
|
||||||
|
public init(kind: BadgeIndicator.Kind = .simple, fillColor: BadgeIndicator.FillColor = .red, expandDirection: ExpandDirection = .right, size: BadgeIndicator.Size = .xxlarge, maximumDigits: BadgeIndicator.MaximumDigits = .two, width: CGFloat? = nil, height: CGFloat? = nil, number: Int? = nil, leadingCharacter: String = "", trailingText: String = "", dotSize: CGFloat? = nil, verticalPadding: CGFloat? = nil, horizontalPadding: CGFloat? = nil, hideDot: Bool = false, hideBorder: Bool = false) {
|
||||||
|
self.kind = kind
|
||||||
|
self.fillColor = fillColor
|
||||||
|
self.expandDirection = expandDirection
|
||||||
|
self.size = size
|
||||||
|
self.maximumDigits = maximumDigits
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.number = number
|
||||||
|
self.leadingCharacter = leadingCharacter
|
||||||
|
self.trailingText = trailingText
|
||||||
|
self.dotSize = dotSize
|
||||||
|
self.verticalPadding = verticalPadding
|
||||||
|
self.horizontalPadding = horizontalPadding
|
||||||
|
self.hideDot = hideDot
|
||||||
|
self.hideBorder = hideBorder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
VDS/Components/Icon/ButtonIcon/ButtonIconChangeLog.txt
Normal file
79
VDS/Components/Icon/ButtonIcon/ButtonIconChangeLog.txt
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
03/30/2023
|
||||||
|
----------------
|
||||||
|
- Dev handoff
|
||||||
|
|
||||||
|
04/06/2023
|
||||||
|
----------------
|
||||||
|
- Changed component name to Button Icon.
|
||||||
|
|
||||||
|
04/13/2023
|
||||||
|
----------------
|
||||||
|
- Dev handoff (additional states)
|
||||||
|
|
||||||
|
04/20/2023
|
||||||
|
----------------
|
||||||
|
- Added Selectable and Selected properties in Configuration.
|
||||||
|
|
||||||
|
05/01/2023
|
||||||
|
----------------
|
||||||
|
- Added fitToIcon prop for Ghost variation.
|
||||||
|
|
||||||
|
05/03/2023
|
||||||
|
----------------
|
||||||
|
- Updated drop shadows for light and dark floating buttons (all states)
|
||||||
|
- Removed border from all floating buttons
|
||||||
|
- Updated all dark floating button backgrounds to gray.20
|
||||||
|
- Disabled icons on gray.20 changed to palette.black 70% opacity for floating buttons
|
||||||
|
- Reduce Inside focusborderPosition to 1px
|
||||||
|
|
||||||
|
05/25/2023
|
||||||
|
----------------
|
||||||
|
- Added hideBorder prop back to Configurations
|
||||||
|
- Added showBadgeIndicator prop to Configurations
|
||||||
|
- Added Hit Area support for Button Icon with Badge Indicator
|
||||||
|
- Added Elements page for Badge Indicator with default settings and offset information
|
||||||
|
- Updated Badge Indicator Offset to be based on center of Icon container
|
||||||
|
|
||||||
|
05/30/2023
|
||||||
|
----------------
|
||||||
|
- Added expandDirection prop to Configurations under Badge Indicator section.
|
||||||
|
|
||||||
|
06/02/2023
|
||||||
|
----------------
|
||||||
|
- Added Additional Border Color specification if hideBorder=True on Low Contrast hover states.
|
||||||
|
|
||||||
|
06/12/2023
|
||||||
|
----------------
|
||||||
|
- Ghost Icon Cart position updated from {1,2} to {1,1}.
|
||||||
|
|
||||||
|
06/13/2023
|
||||||
|
----------------
|
||||||
|
- Updated Drop shadow properties layout in States.
|
||||||
|
|
||||||
|
06/29/2023
|
||||||
|
----------------
|
||||||
|
- Updated Badge Indicator simple dot size to 4px.
|
||||||
|
|
||||||
|
08/18/2023
|
||||||
|
----------------
|
||||||
|
- Updated default icon color for all selected Button Icon states to element.primary.onlight for light surfaces and element.primary.ondark for dark surfaces.
|
||||||
|
- Added a dev note that this default color can be set to a custom color (like red).
|
||||||
|
|
||||||
|
11/16/2023
|
||||||
|
----------------
|
||||||
|
- Added component tokens
|
||||||
|
- Applied component tokens throughout states
|
||||||
|
- Applied semantic inverse to primary element, background states on light and dark surfaces
|
||||||
|
|
||||||
|
12/1/2023
|
||||||
|
----------------
|
||||||
|
- Reapplied component token updates to Ghost States
|
||||||
|
|
||||||
|
1/9/2024
|
||||||
|
----------------
|
||||||
|
- Fixed incorrect Low Contrast border token
|
||||||
|
|
||||||
|
1/25/2024
|
||||||
|
----------------
|
||||||
|
- Removed redundant opacity specs in States (dark surface).
|
||||||
Loading…
Reference in New Issue
Block a user