Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios.git into feature/textLink
This commit is contained in:
commit
a5cd93b71c
@ -44,6 +44,7 @@
|
||||
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; };
|
||||
EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; };
|
||||
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */; };
|
||||
EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */; };
|
||||
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */; };
|
||||
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEB628ECC03A003B3210 /* ToolTipLabelAttribute.swift */; };
|
||||
EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAA5EEB828ECD24B003B3210 /* Icons.xcassets */; };
|
||||
@ -130,6 +131,7 @@
|
||||
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>"; };
|
||||
EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroup.swift; sourceTree = "<group>"; };
|
||||
EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyLabelAttribute.swift; sourceTree = "<group>"; };
|
||||
EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageLabelAttribute.swift; sourceTree = "<group>"; };
|
||||
EAA5EEB628ECC03A003B3210 /* ToolTipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolTipLabelAttribute.swift; sourceTree = "<group>"; };
|
||||
EAA5EEB828ECD24B003B3210 /* Icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Icons.xcassets; sourceTree = "<group>"; };
|
||||
@ -480,6 +482,7 @@
|
||||
children = (
|
||||
EAF7F0A3289B017C00B287F5 /* LabelAttributeModel.swift */,
|
||||
EAF7F0B2289B1ADC00B287F5 /* ActionLabelAttribute.swift */,
|
||||
EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */,
|
||||
EAF7F13228A2A16500B287F5 /* AttachmentLabelAttributeModel.swift */,
|
||||
EAF7F0B0289B177F00B287F5 /* ColorLabelAttribute.swift */,
|
||||
EAF7F0AA289B13FD00B287F5 /* FontLabelAttribute.swift */,
|
||||
@ -631,6 +634,7 @@
|
||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||
EA3361C5289030FC0071C351 /* Accessable.swift in Sources */,
|
||||
EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */,
|
||||
EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */,
|
||||
EAF7F11728A1475A00B287F5 /* RadioButton.swift in Sources */,
|
||||
EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */,
|
||||
|
||||
@ -86,7 +86,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable {
|
||||
open func reset() {
|
||||
backgroundColor = .clear
|
||||
surface = .light
|
||||
disabled = false
|
||||
disabled = false
|
||||
}
|
||||
|
||||
// MARK: - ViewProtocol
|
||||
@ -94,5 +94,5 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable {
|
||||
open func setup() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
insetsLayoutMarginsFromSafeArea = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,11 @@ public class SelectorGroupHandlerBase<HandlerType: Control>: Control {
|
||||
self?.sendActions(for: .valueChanged)
|
||||
}
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
selectorViews.forEach{ $0.reset() }
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectorGroupSelectedHandlerBase<HandlerType: Control>: SelectorGroupHandlerBase<HandlerType>{
|
||||
|
||||
@ -18,7 +18,13 @@ public enum BadgeFillColor: String, Codable, CaseIterable {
|
||||
@objc(VDSBadge)
|
||||
public class Badge: View, Accessable {
|
||||
|
||||
private var label = Label()
|
||||
private var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.adjustsFontSizeToFitWidth = false
|
||||
$0.lineBreakMode = .byTruncatingTail
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BoldBodySmall
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
@ -62,8 +68,6 @@ public class Badge: View, Accessable {
|
||||
addSubview(label)
|
||||
|
||||
layer.cornerRadius = 2
|
||||
label.adjustsFontSizeToFitWidth = false
|
||||
label.lineBreakMode = .byTruncatingTail
|
||||
|
||||
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4).isActive = true
|
||||
label.topAnchor.constraint(equalTo: topAnchor, constant: 2).isActive = true
|
||||
@ -73,10 +77,27 @@ public class Badge: View, Accessable {
|
||||
maxWidthConstraint = label.widthAnchor.constraint(lessThanOrEqualToConstant: 100)
|
||||
minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23)
|
||||
minWidthConstraint?.isActive = true
|
||||
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
label.lineBreakMode = .byTruncatingTail
|
||||
label.textPosition = .left
|
||||
label.typograpicalStyle = .BoldBodySmall
|
||||
|
||||
fillColor = .red
|
||||
text = ""
|
||||
maxWidth = nil
|
||||
numberOfLines = 1
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
@ -160,10 +181,9 @@ public class Badge: View, Accessable {
|
||||
//--------------------------------------------------
|
||||
open override func updateView() {
|
||||
backgroundColor = backgroundColor()
|
||||
|
||||
label.textColorConfiguration = textColorConfiguration()
|
||||
label.numberOfLines = numberOfLines
|
||||
label.textPosition = .left
|
||||
label.typograpicalStyle = .BoldBodySmall
|
||||
label.text = text
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
|
||||
@ -83,7 +83,10 @@ open class TextLink: Control {
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
size = .large
|
||||
text = nil
|
||||
|
||||
accessibilityCustomActions = []
|
||||
accessibilityTraits = .staticText
|
||||
}
|
||||
|
||||
@ -96,6 +96,12 @@ open class TextLinkCaret: Control {
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
|
||||
label.typograpicalStyle = TypographicalStyle.BoldBodyLarge
|
||||
text = nil
|
||||
iconPosition = .right
|
||||
|
||||
accessibilityCustomActions = []
|
||||
accessibilityTraits = .staticText
|
||||
}
|
||||
|
||||
@ -51,47 +51,51 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
}
|
||||
|
||||
private var shouldShowLabels: Bool {
|
||||
guard labelText?.isEmpty == false || childText?.isEmpty == false else { return false }
|
||||
guard labelText?.isEmpty == false || childText?.isEmpty == false || labelAttributedText?.string.isEmpty == false || childAttributedText?.string.isEmpty == false else { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
private var mainStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
}
|
||||
}()
|
||||
private var mainStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
}
|
||||
|
||||
private var selectorStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
}
|
||||
}()
|
||||
private var selectorStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
}
|
||||
|
||||
private var selectorLabelStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
}
|
||||
}()
|
||||
private var selectorLabelStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
}
|
||||
|
||||
private var primaryLabel = Label()
|
||||
private var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BoldBodyLarge
|
||||
}
|
||||
|
||||
private var secondaryLabel = Label()
|
||||
private var childLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodyLarge
|
||||
}
|
||||
|
||||
private var errorLabel = Label()
|
||||
private var errorLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodyMedium
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var selectorView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
public var selectorView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
//can't bind to @Proxy
|
||||
open override var isSelected: Bool { didSet { didChange() }}
|
||||
@ -99,11 +103,27 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
open var labelText: String? { didSet { didChange() }}
|
||||
|
||||
open var labelTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var labelAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true)
|
||||
label.attributedText = labelAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var childText: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var childTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var childAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true)
|
||||
childLabel.attributedText = childAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var showError: Bool = false { didSet { didChange() }}
|
||||
|
||||
open var errorText: String? { didSet { didChange() }}
|
||||
@ -158,8 +178,8 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
mainStackView.addArrangedSubview(errorLabel)
|
||||
selectorStackView.addArrangedSubview(selectorView)
|
||||
selectorStackView.addArrangedSubview(selectorLabelStackView)
|
||||
selectorLabelStackView.addArrangedSubview(primaryLabel)
|
||||
selectorLabelStackView.addArrangedSubview(secondaryLabel)
|
||||
selectorLabelStackView.addArrangedSubview(label)
|
||||
selectorLabelStackView.addArrangedSubview(childLabel)
|
||||
|
||||
let selectorSize = getSelectorSize()
|
||||
selectorHeightConstraint = selectorView.heightAnchor.constraint(equalToConstant: selectorSize.height)
|
||||
@ -184,28 +204,31 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
//add the stackview to hold the 2 labels
|
||||
//top label
|
||||
if let labelText {
|
||||
primaryLabel.textPosition = .left
|
||||
primaryLabel.typograpicalStyle = .BoldBodyLarge
|
||||
primaryLabel.text = labelText
|
||||
primaryLabel.surface = surface
|
||||
primaryLabel.disabled = disabled
|
||||
primaryLabel.attributes = labelTextAttributes
|
||||
primaryLabel.isHidden = false
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
label.attributes = labelTextAttributes
|
||||
label.text = labelText
|
||||
label.isHidden = false
|
||||
} else if labelAttributedText != nil {
|
||||
label.isHidden = false
|
||||
|
||||
} else {
|
||||
primaryLabel.isHidden = true
|
||||
label.isHidden = true
|
||||
}
|
||||
|
||||
//bottom label
|
||||
if let childText {
|
||||
secondaryLabel.textPosition = .left
|
||||
secondaryLabel.typograpicalStyle = .BodyLarge
|
||||
secondaryLabel.text = childText
|
||||
secondaryLabel.surface = surface
|
||||
secondaryLabel.disabled = disabled
|
||||
secondaryLabel.attributes = childTextAttributes
|
||||
secondaryLabel.isHidden = false
|
||||
childLabel.text = childText
|
||||
childLabel.surface = surface
|
||||
childLabel.disabled = disabled
|
||||
childLabel.attributes = childTextAttributes
|
||||
childLabel.isHidden = false
|
||||
|
||||
} else if childAttributedText != nil {
|
||||
childLabel.isHidden = false
|
||||
|
||||
} else {
|
||||
secondaryLabel.isHidden = true
|
||||
childLabel.isHidden = true
|
||||
}
|
||||
selectorStackView.spacing = 12
|
||||
selectorLabelStackView.spacing = 4
|
||||
@ -219,8 +242,6 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
|
||||
//either add/remove the error from the main stack
|
||||
if let errorText, shouldShowError {
|
||||
errorLabel.textPosition = .left
|
||||
errorLabel.typograpicalStyle = .BodyMedium
|
||||
errorLabel.text = errorText
|
||||
errorLabel.surface = surface
|
||||
errorLabel.disabled = disabled
|
||||
@ -232,8 +253,37 @@ open class CheckboxBase: Control, Accessable, DataTrackable, BinaryColorable, Er
|
||||
}
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
childLabel.reset()
|
||||
errorLabel.reset()
|
||||
|
||||
label.typograpicalStyle = .BoldBodyLarge
|
||||
childLabel.typograpicalStyle = .BodyLarge
|
||||
errorLabel.typograpicalStyle = .BodyMedium
|
||||
|
||||
labelText = nil
|
||||
labelTextAttributes = nil
|
||||
labelAttributedText = nil
|
||||
childText = nil
|
||||
childTextAttributes = nil
|
||||
childAttributedText = nil
|
||||
showError = false
|
||||
errorText = nil
|
||||
inputId = nil
|
||||
value = nil
|
||||
dataAnalyticsTrack = nil
|
||||
dataClickStream = nil
|
||||
dataTrack = nil
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
isSelected = false
|
||||
|
||||
updateSelector()
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
36
VDS/Components/Label/Attributes/AnyLabelAttribute.swift
Normal file
36
VDS/Components/Label/Attributes/AnyLabelAttribute.swift
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// AnyAttribute.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 11/10/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct AnyAttribute: LabelAttributeModel {
|
||||
public var id = UUID()
|
||||
public var location: Int
|
||||
public var length: Int
|
||||
public var key: NSAttributedString.Key
|
||||
public var value: AnyHashable
|
||||
|
||||
public init(location: Int, length: Int, key: NSAttributedString.Key, value: AnyHashable) {
|
||||
self.location = location
|
||||
self.length = length
|
||||
self.key = key
|
||||
self.value = value
|
||||
}
|
||||
|
||||
public func isEqual(_ equatable: AnyAttribute) -> Bool {
|
||||
return id == equatable.id && range == equatable.range && key == equatable.key && value == equatable.value
|
||||
}
|
||||
|
||||
public static func == (lhs: AnyAttribute, rhs: AnyAttribute) -> Bool {
|
||||
lhs.isEqual(rhs)
|
||||
}
|
||||
|
||||
public func setAttribute(on attributedString: NSMutableAttributedString) {
|
||||
attributedString.removeAttribute(key, range: range)
|
||||
attributedString.addAttribute(key, value: value, range: range)
|
||||
}
|
||||
}
|
||||
@ -19,17 +19,20 @@ public struct ColorLabelAttribute: LabelAttributeModel {
|
||||
public var location: Int
|
||||
public var length: Int
|
||||
public var color: UIColor
|
||||
public var isForegroundColor: Bool
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
public init(location: Int, length: Int, color: UIColor = .black) {
|
||||
public init(location: Int, length: Int, color: UIColor = .black, isForegroundColor: Bool = true) {
|
||||
self.location = location
|
||||
self.length = length
|
||||
self.color = color
|
||||
self.isForegroundColor = isForegroundColor
|
||||
}
|
||||
|
||||
public func setAttribute(on attributedString: NSMutableAttributedString) {
|
||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||
attributedString.addAttribute(.foregroundColor, value: color, range: range)
|
||||
let attributeKey = isForegroundColor ? NSAttributedString.Key.foregroundColor : NSAttributedString.Key.backgroundColor
|
||||
attributedString.removeAttribute(attributeKey, range: range)
|
||||
attributedString.addAttribute(attributeKey, value: color, range: range)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,21 +24,59 @@ public struct FontLabelAttribute: LabelAttributeModel {
|
||||
public var length: Int
|
||||
public var style: TypographicalStyle
|
||||
public var color: UIColor
|
||||
public var textPosition: TextPosition
|
||||
public var lineBreakMode: NSLineBreakMode
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
public init(location: Int, length: Int, style: TypographicalStyle, color: UIColor = .black) {
|
||||
public init(location: Int, length: Int, style: TypographicalStyle, color: UIColor = .black, textPosition: TextPosition = .left, lineBreakMode: NSLineBreakMode = .byWordWrapping) {
|
||||
self.location = location
|
||||
self.length = length
|
||||
self.style = style
|
||||
self.color = color
|
||||
self.textPosition = textPosition
|
||||
self.lineBreakMode = lineBreakMode
|
||||
}
|
||||
|
||||
public func setAttribute(on attributedString: NSMutableAttributedString) {
|
||||
|
||||
attributedString.removeAttribute(.font, range: range)
|
||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||
attributedString.addAttribute(.font, value: style.font, range: range)
|
||||
attributedString.addAttribute(.foregroundColor, value: color, range: range)
|
||||
setStyleAttributes(attributedString)
|
||||
}
|
||||
|
||||
private func setStyleAttributes(_ attributedString: NSMutableAttributedString) {
|
||||
//set letterSpacing
|
||||
if style.letterSpacing > 0.0 {
|
||||
attributedString.removeAttribute(.kern, range: range)
|
||||
attributedString.addAttribute(.kern, value: style.letterSpacing, range: range)
|
||||
}
|
||||
|
||||
//set lineHeight
|
||||
if style.lineHeight > 0.0 {
|
||||
let lineHeight = style.lineHeight
|
||||
let adjustment = lineHeight > style.font.lineHeight ? 2.0 : 1.0
|
||||
let baselineOffset = (lineHeight - style.font.lineHeight) / 2.0 / adjustment
|
||||
let paragraph = NSMutableParagraphStyle().with {
|
||||
$0.maximumLineHeight = lineHeight
|
||||
$0.minimumLineHeight = lineHeight
|
||||
$0.alignment = textPosition.textAlignment
|
||||
$0.lineBreakMode = lineBreakMode
|
||||
}
|
||||
attributedString.removeAttribute(.baselineOffset, range: range)
|
||||
attributedString.removeAttribute(.paragraphStyle, range: range)
|
||||
attributedString.addAttribute(.baselineOffset, value: baselineOffset, range: range)
|
||||
attributedString.addAttribute(.paragraphStyle, value: paragraph, range: range)
|
||||
|
||||
} else if textPosition != .left {
|
||||
let paragraph = NSMutableParagraphStyle().with {
|
||||
$0.alignment = textPosition.textAlignment
|
||||
$0.lineBreakMode = lineBreakMode
|
||||
}
|
||||
attributedString.removeAttribute(.paragraphStyle, range: range)
|
||||
attributedString.addAttribute(.paragraphStyle, value: paragraph, range: range)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -22,5 +22,28 @@ extension LabelAttributeModel {
|
||||
public static func == (lhs: any LabelAttributeModel, rhs: any LabelAttributeModel) -> Bool {
|
||||
lhs.isEqual(rhs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension NSAttributedString {
|
||||
func createAttributeModels() -> [(any LabelAttributeModel)] {
|
||||
var attributes: [any VDS.LabelAttributeModel] = []
|
||||
enumerateAttributes(in: NSMakeRange(0, length)) { attributeMap, range, stop in
|
||||
attributeMap.forEach { (key: NSAttributedString.Key, value: Any) in
|
||||
if let attribute = NSAttributedString.createAttributeModelFor(key: key, range: range, value: value) {
|
||||
attributes.append(attribute)
|
||||
}
|
||||
}
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
|
||||
static func createAttributeModelFor(key: NSAttributedString.Key, range: NSRange, value: Any) -> (any LabelAttributeModel)? {
|
||||
guard let value = value as? AnyHashable else { return nil }
|
||||
|
||||
guard let font = value as? UIFont, let style = TypographicalStyle.style(for: font.fontName, size: font.pointSize), key == .font
|
||||
else {
|
||||
return AnyAttribute(location: range.location, length: range.length, key: key, value: value)
|
||||
}
|
||||
return FontLabelAttribute(location: range.location, length: range.length, style: style)
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,8 @@ open class LabelBase: UILabel, Handlerable, ViewProtocol, Resettable {
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
private var initialSetupPerformed = false
|
||||
|
||||
open var useAttributedText: Bool = false
|
||||
|
||||
open var surface: Surface = .light { didSet { didChange() }}
|
||||
|
||||
@ -119,49 +121,53 @@ open class LabelBase: UILabel, Handlerable, ViewProtocol, Resettable {
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
open func updateView() {
|
||||
textAlignment = textPosition.textAlignment
|
||||
textColor = textColorConfiguration.getColor(self)
|
||||
font = typograpicalStyle.font
|
||||
if !useAttributedText {
|
||||
textAlignment = textPosition.textAlignment
|
||||
textColor = textColorConfiguration.getColor(self)
|
||||
font = typograpicalStyle.font
|
||||
|
||||
if let text = text, let font = font, let textColor = textColor {
|
||||
//clear the arrays holding actions
|
||||
accessibilityCustomActions = []
|
||||
|
||||
//create the primary string
|
||||
let startingAttributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor]
|
||||
let mutableText = NSMutableAttributedString(string: text, attributes: startingAttributes)
|
||||
|
||||
//set the local lineHeight/lineSpacing attributes
|
||||
setStyleAttributes(attributedString: mutableText)
|
||||
|
||||
applyAttributes(mutableText)
|
||||
|
||||
//set the attributed text
|
||||
attributedText = mutableText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let text = text, let font = font, let textColor = textColor {
|
||||
//clear the arrays holding actions
|
||||
accessibilityCustomActions = []
|
||||
actions = []
|
||||
|
||||
//create the primary string
|
||||
let startingAttributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor]
|
||||
let mutableText = NSMutableAttributedString(string: text, attributes: startingAttributes)
|
||||
|
||||
//set the local lineHeight/lineSpacing attributes
|
||||
setStyleAttributes(attributedString: mutableText)
|
||||
|
||||
if let attributes = attributes {
|
||||
//loop through the models attributes
|
||||
for attribute in attributes {
|
||||
// MARK: - Private Attributes
|
||||
private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) {
|
||||
actions = []
|
||||
|
||||
if let attributes = attributes {
|
||||
//loop through the models attributes
|
||||
for attribute in attributes {
|
||||
|
||||
//add attribute on the string
|
||||
attribute.setAttribute(on: mutableAttributedString)
|
||||
|
||||
//see if the attribute is Actionable
|
||||
if let actionable = attribute as? any ActionLabelAttributeModel{
|
||||
//create a accessibleAction
|
||||
let customAccessibilityAction = customAccessibilityAction(range: actionable.range, accessibleText: actionable.accessibleText)
|
||||
|
||||
//add attribute on the string
|
||||
attribute.setAttribute(on: mutableText)
|
||||
|
||||
//see if the attribute is Actionable
|
||||
if let actionable = attribute as? any ActionLabelAttributeModel{
|
||||
//create a accessibleAction
|
||||
let customAccessibilityAction = customAccessibilityAction(range: actionable.range, accessibleText: actionable.accessibleText)
|
||||
|
||||
//create a wrapper for the attributes range, block and
|
||||
actions.append(LabelAction(range: actionable.range, action: actionable.action, accessibilityID: customAccessibilityAction?.hashValue ?? -1))
|
||||
}
|
||||
//create a wrapper for the attributes range, block and
|
||||
actions.append(LabelAction(range: actionable.range, action: actionable.action, accessibilityID: customAccessibilityAction?.hashValue ?? -1))
|
||||
}
|
||||
}
|
||||
|
||||
//only enabled if enabled and has actions
|
||||
isUserInteractionEnabled = !disabled && !actions.isEmpty
|
||||
|
||||
//set the attributed text
|
||||
attributedText = mutableText
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private Attributes
|
||||
private func setStyleAttributes(attributedString: NSMutableAttributedString) {
|
||||
//get the range
|
||||
let entireRange = NSRange(location: 0, length: attributedString.length)
|
||||
|
||||
@ -46,57 +46,88 @@ open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var mainStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
$0.spacing = 0
|
||||
}
|
||||
}()
|
||||
|
||||
private var selectorStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
}
|
||||
}()
|
||||
|
||||
private var selectorLeftLabelStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
}
|
||||
}()
|
||||
|
||||
private var textLabel = Label()
|
||||
|
||||
private var subTextLabel = Label()
|
||||
private var mainStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
$0.spacing = 0
|
||||
}
|
||||
|
||||
private var subTextRightLabel = Label()
|
||||
private var selectorStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
$0.spacing = 12
|
||||
}
|
||||
|
||||
private var selectorLeftLabelStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
$0.spacing = 4
|
||||
$0.isHidden = false
|
||||
}
|
||||
|
||||
private var textLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BoldBodyLarge
|
||||
}
|
||||
|
||||
private var subTextLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodyLarge
|
||||
}
|
||||
|
||||
private var subTextRightLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .right
|
||||
$0.typograpicalStyle = .BodyLarge
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var selectorView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
|
||||
public var selectorView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
open var text: String = "Default Text" { didSet { didChange() }}
|
||||
|
||||
open var textAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
open var textAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
textLabel.useAttributedText = !(textAttributedText?.string.isEmpty ?? true)
|
||||
textLabel.attributedText = textAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var subText: String? { didSet { didChange() }}
|
||||
|
||||
open var subTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
open var subTextAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
subTextLabel.useAttributedText = !(subTextAttributedText?.string.isEmpty ?? true)
|
||||
subTextLabel.attributedText = subTextAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var subTextRight: String? { didSet { didChange() }}
|
||||
|
||||
open var subTextRightAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
open var subTextRightAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
subTextRightLabel.useAttributedText = !(subTextRightAttributedText?.string.isEmpty ?? true)
|
||||
subTextRightLabel.attributedText = subTextRightAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var strikethrough: Bool = false { didSet { didChange() }}
|
||||
|
||||
open var inputId: String? { didSet { didChange() }}
|
||||
@ -147,10 +178,6 @@ open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
||||
selectorLeftLabelStackView.addArrangedSubview(textLabel)
|
||||
selectorLeftLabelStackView.addArrangedSubview(subTextLabel)
|
||||
|
||||
selectorStackView.spacing = 12
|
||||
selectorLeftLabelStackView.spacing = 4
|
||||
selectorLeftLabelStackView.isHidden = false
|
||||
|
||||
updateSelector()
|
||||
|
||||
selectorView.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
@ -162,15 +189,12 @@ open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
||||
mainStackView.leadingAnchor.constraint(equalTo: selectorView.leadingAnchor, constant: 16).isActive = true
|
||||
mainStackView.trailingAnchor.constraint(equalTo: selectorView.trailingAnchor, constant: -16).isActive = true
|
||||
mainStackView.bottomAnchor.constraint(equalTo: selectorView.bottomAnchor, constant: -16).isActive = true
|
||||
|
||||
}
|
||||
|
||||
func updateLabels() {
|
||||
|
||||
//add the stackview to hold the 2 labels
|
||||
//text label
|
||||
textLabel.textPosition = .left
|
||||
textLabel.typograpicalStyle = .BoldBodyLarge
|
||||
textLabel.text = text
|
||||
textLabel.surface = surface
|
||||
textLabel.disabled = disabled
|
||||
@ -178,26 +202,30 @@ open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
||||
|
||||
//subText label
|
||||
if let subText {
|
||||
subTextLabel.textPosition = .left
|
||||
subTextLabel.typograpicalStyle = .BodyLarge
|
||||
subTextLabel.text = subText
|
||||
subTextLabel.surface = surface
|
||||
subTextLabel.disabled = disabled
|
||||
subTextLabel.attributes = subTextAttributes
|
||||
subTextLabel.isHidden = false
|
||||
|
||||
} else if subTextAttributedText != nil {
|
||||
subTextLabel.isHidden = false
|
||||
|
||||
} else {
|
||||
subTextLabel.isHidden = true
|
||||
}
|
||||
|
||||
//subTextRight label
|
||||
if let subTextRight {
|
||||
subTextRightLabel.textPosition = .right
|
||||
subTextRightLabel.typograpicalStyle = .BodyLarge
|
||||
subTextRightLabel.text = subTextRight
|
||||
subTextRightLabel.surface = surface
|
||||
subTextRightLabel.disabled = disabled
|
||||
subTextRightLabel.attributes = subTextRightAttributes
|
||||
subTextRightLabel.isHidden = false
|
||||
|
||||
} else if subTextAttributedText != nil {
|
||||
subTextRightLabel.isHidden = false
|
||||
|
||||
} else {
|
||||
subTextRightLabel.isHidden = true
|
||||
}
|
||||
@ -205,6 +233,38 @@ open class RadioBoxBase: Control, BinaryColorable, Accessable, DataTrackable{
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
textLabel.reset()
|
||||
subTextLabel.reset()
|
||||
subTextRightLabel.reset()
|
||||
|
||||
textLabel.typograpicalStyle = .BoldBodyLarge
|
||||
subTextLabel.typograpicalStyle = .BodyLarge
|
||||
subTextRightLabel.typograpicalStyle = .BodyLarge
|
||||
|
||||
text = "Default Text"
|
||||
textAttributes = nil
|
||||
textAttributedText = nil
|
||||
subText = nil
|
||||
subTextAttributes = nil
|
||||
subTextAttributedText = nil
|
||||
subTextRight = nil
|
||||
subTextRightAttributes = nil
|
||||
subTextRightAttributedText = nil
|
||||
strikethrough = false
|
||||
inputId = nil
|
||||
value = nil
|
||||
dataAnalyticsTrack = nil
|
||||
dataClickStream = nil
|
||||
dataTrack = nil
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
|
||||
isSelected = false
|
||||
|
||||
updateSelector()
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
@ -59,70 +59,90 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
}
|
||||
|
||||
private var shouldShowLabels: Bool {
|
||||
guard labelText?.isEmpty == false || childText?.isEmpty == false else { return false }
|
||||
guard labelText?.isEmpty == false || childText?.isEmpty == false || labelAttributedText?.string.isEmpty == false || childAttributedText?.string.isEmpty == false else { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
private var mainStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
}
|
||||
}()
|
||||
|
||||
private var selectorStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
}
|
||||
}()
|
||||
private var mainStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .vertical
|
||||
}
|
||||
|
||||
private var selectorLabelStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
}
|
||||
}()
|
||||
private var selectorStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.axis = .horizontal
|
||||
}
|
||||
|
||||
private var primaryLabel = Label()
|
||||
private var selectorLabelStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
}
|
||||
|
||||
private var secondaryLabel = Label()
|
||||
private var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BoldBodyLarge
|
||||
}
|
||||
|
||||
private var childLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodyLarge
|
||||
}
|
||||
|
||||
private var errorLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodyMedium
|
||||
}
|
||||
|
||||
private var errorLabel = Label()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var selectorView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
|
||||
public var selectorView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
open var labelText: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var labelTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var labelAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true)
|
||||
label.attributedText = labelAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var childText: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var childTextAttributes: [any LabelAttributeModel]? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var childAttributedText: NSAttributedString? {
|
||||
didSet {
|
||||
childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true)
|
||||
childLabel.attributedText = childAttributedText
|
||||
didChange()
|
||||
}
|
||||
}
|
||||
|
||||
open var showError: Bool = false { didSet { didChange() }}
|
||||
|
||||
open var errorText: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var inputId: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var value: AnyHashable? { didSet { didChange() }}
|
||||
|
||||
open var dataAnalyticsTrack: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var dataClickStream: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var dataTrack: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
open var accessibilityHintEnabled: String? { didSet { didChange() }}
|
||||
|
||||
open var accessibilityHintDisabled: String? { didSet { didChange() }}
|
||||
@ -134,7 +154,7 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
open var accessibilityLabelEnabled: String? { didSet { didChange() }}
|
||||
|
||||
open var accessibilityLabelDisabled: String? { didSet { didChange() }}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
@ -146,7 +166,7 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
@ -163,54 +183,58 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
mainStackView.addArrangedSubview(errorLabel)
|
||||
selectorStackView.addArrangedSubview(selectorView)
|
||||
selectorStackView.addArrangedSubview(selectorLabelStackView)
|
||||
selectorLabelStackView.addArrangedSubview(primaryLabel)
|
||||
selectorLabelStackView.addArrangedSubview(secondaryLabel)
|
||||
|
||||
selectorLabelStackView.addArrangedSubview(label)
|
||||
selectorLabelStackView.addArrangedSubview(childLabel)
|
||||
|
||||
let selectorSize = getSelectorSize()
|
||||
selectorHeightConstraint = selectorView.heightAnchor.constraint(equalToConstant: selectorSize.height)
|
||||
selectorHeightConstraint?.isActive = true
|
||||
|
||||
selectorWidthConstraint = selectorView.widthAnchor.constraint(equalToConstant: selectorSize.width)
|
||||
selectorWidthConstraint?.isActive = true
|
||||
|
||||
|
||||
updateSelector()
|
||||
|
||||
mainStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
mainStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||
mainStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
||||
mainStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||
|
||||
|
||||
}
|
||||
|
||||
func updateLabels() {
|
||||
|
||||
|
||||
//deal with labels
|
||||
if shouldShowLabels {
|
||||
//add the stackview to hold the 2 labels
|
||||
//top label
|
||||
if let labelText {
|
||||
primaryLabel.textPosition = .left
|
||||
primaryLabel.typograpicalStyle = .BoldBodyLarge
|
||||
primaryLabel.text = labelText
|
||||
primaryLabel.surface = surface
|
||||
primaryLabel.disabled = disabled
|
||||
primaryLabel.attributes = labelTextAttributes
|
||||
primaryLabel.isHidden = false
|
||||
label.text = labelText
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
label.attributes = labelTextAttributes
|
||||
label.isHidden = false
|
||||
|
||||
} else if labelAttributedText != nil {
|
||||
label.isHidden = false
|
||||
|
||||
} else {
|
||||
primaryLabel.isHidden = true
|
||||
label.isHidden = true
|
||||
}
|
||||
|
||||
//bottom label
|
||||
if let childText {
|
||||
secondaryLabel.textPosition = .left
|
||||
secondaryLabel.typograpicalStyle = .BodyLarge
|
||||
secondaryLabel.text = childText
|
||||
secondaryLabel.surface = surface
|
||||
secondaryLabel.disabled = disabled
|
||||
secondaryLabel.attributes = childTextAttributes
|
||||
secondaryLabel.isHidden = false
|
||||
childLabel.text = childText
|
||||
childLabel.surface = surface
|
||||
childLabel.disabled = disabled
|
||||
childLabel.attributes = childTextAttributes
|
||||
childLabel.isHidden = false
|
||||
|
||||
} else if childAttributedText != nil {
|
||||
childLabel.isHidden = false
|
||||
|
||||
} else {
|
||||
secondaryLabel.isHidden = true
|
||||
childLabel.isHidden = true
|
||||
}
|
||||
selectorStackView.spacing = 12
|
||||
selectorLabelStackView.spacing = 4
|
||||
@ -224,8 +248,6 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
|
||||
//either add/remove the error from the main stack
|
||||
if let errorText, shouldShowError {
|
||||
errorLabel.textPosition = .left
|
||||
errorLabel.typograpicalStyle = .BodyMedium
|
||||
errorLabel.text = errorText
|
||||
errorLabel.surface = surface
|
||||
errorLabel.disabled = disabled
|
||||
@ -240,14 +262,44 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
childLabel.reset()
|
||||
errorLabel.reset()
|
||||
|
||||
label.typograpicalStyle = .BoldBodyLarge
|
||||
childLabel.typograpicalStyle = .BodyLarge
|
||||
errorLabel.typograpicalStyle = .BodyMedium
|
||||
|
||||
labelText = nil
|
||||
labelTextAttributes = nil
|
||||
labelAttributedText = nil
|
||||
childText = nil
|
||||
childTextAttributes = nil
|
||||
childAttributedText = nil
|
||||
showError = false
|
||||
errorText = nil
|
||||
inputId = nil
|
||||
value = nil
|
||||
dataAnalyticsTrack = nil
|
||||
dataClickStream = nil
|
||||
dataTrack = nil
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
|
||||
isSelected = false
|
||||
|
||||
updateSelector()
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
|
||||
/// This will checkbox the state of the Selector and execute the actionBlock if provided.
|
||||
open func toggle() {
|
||||
guard !isSelected else { return }
|
||||
|
||||
|
||||
//removed error
|
||||
if showError && isSelected == false {
|
||||
showError.toggle()
|
||||
@ -255,10 +307,10 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
isSelected.toggle()
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - State
|
||||
//--------------------------------------------------
|
||||
//--------------------------------------------------
|
||||
open override func updateView() {
|
||||
updateLabels()
|
||||
updateSelector()
|
||||
@ -323,7 +375,7 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
let bounds = selectorView.bounds
|
||||
let length = max(bounds.size.height, bounds.size.width)
|
||||
guard length > 0.0, shapeLayer == nil else { return }
|
||||
|
||||
|
||||
//get the colors
|
||||
let backgroundColor = radioButtonBackgroundColorConfiguration.getColor(self)
|
||||
let borderColor = radioButtonBorderColorConfiguration.getColor(self)
|
||||
@ -337,9 +389,9 @@ open class RadioButtonBase: Control, Accessable, DataTrackable, BinaryColorable,
|
||||
if shapeLayer == nil {
|
||||
let selectedBounds = radioButtonSelectedSize
|
||||
let bezierPath = UIBezierPath(ovalIn: CGRect(x: (bounds.width - selectedBounds.width) / 2,
|
||||
y: (bounds.height - selectedBounds.height) / 2,
|
||||
y: (bounds.height - selectedBounds.height) / 2,
|
||||
width: radioButtonSelectedSize.width,
|
||||
height: radioButtonSelectedSize.height))
|
||||
height: radioButtonSelectedSize.height))
|
||||
let shapeLayer = CAShapeLayer()
|
||||
self.shapeLayer = shapeLayer
|
||||
shapeLayer.frame = bounds
|
||||
|
||||
@ -43,18 +43,14 @@ open class RadioSwatchBase: Control, Accessable, DataTrackable, BinaryColorable
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var selectorView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
|
||||
public var fillView: UIImageView = {
|
||||
return UIImageView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.contentMode = .scaleAspectFit
|
||||
}
|
||||
}()
|
||||
public var selectorView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
public var fillView = UIImageView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.contentMode = .scaleAspectFit
|
||||
}
|
||||
|
||||
open var fillImage: UIImage? { didSet { didChange() }}
|
||||
|
||||
@ -126,6 +122,24 @@ open class RadioSwatchBase: Control, Accessable, DataTrackable, BinaryColorable
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
|
||||
fillImage = nil
|
||||
text = ""
|
||||
primaryColor = nil
|
||||
secondaryColor = nil
|
||||
strikethrough = false
|
||||
inputId = nil
|
||||
value = nil
|
||||
dataAnalyticsTrack = nil
|
||||
dataClickStream = nil
|
||||
dataTrack = nil
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
|
||||
setNeedsDisplay()
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
@ -46,14 +46,20 @@ open class EntryField: Control, Accessable {
|
||||
internal var titleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.attributes = []
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodySmall
|
||||
}
|
||||
|
||||
internal var errorLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodySmall
|
||||
}
|
||||
|
||||
internal var helperLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodySmall
|
||||
}
|
||||
|
||||
internal var containerView: UIView = {
|
||||
@ -256,6 +262,38 @@ open class EntryField: Control, Accessable {
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
titleLabel.reset()
|
||||
errorLabel.reset()
|
||||
helperLabel.reset()
|
||||
|
||||
titleLabel.textPosition = .left
|
||||
titleLabel.typograpicalStyle = .BodySmall
|
||||
errorLabel.textPosition = .left
|
||||
errorLabel.typograpicalStyle = .BodySmall
|
||||
helperLabel.textPosition = .left
|
||||
helperLabel.typograpicalStyle = .BodySmall
|
||||
|
||||
labelText = nil
|
||||
helperText = nil
|
||||
showError = false
|
||||
errorText = nil
|
||||
tooltipTitle = nil
|
||||
tooltipContent = nil
|
||||
transparentBackground = false
|
||||
width = nil
|
||||
maxLength = nil
|
||||
inputId = nil
|
||||
value = nil
|
||||
defaultValue = nil
|
||||
required = false
|
||||
readOnly = false
|
||||
accessibilityHintEnabled = nil
|
||||
accessibilityHintDisabled = nil
|
||||
accessibilityValueEnabled = nil
|
||||
accessibilityValueDisabled = nil
|
||||
accessibilityLabelEnabled = nil
|
||||
accessibilityLabelDisabled = nil
|
||||
|
||||
setAccessibilityLabel()
|
||||
}
|
||||
|
||||
@ -313,8 +351,6 @@ open class EntryField: Control, Accessable {
|
||||
}
|
||||
|
||||
//set the titleLabel
|
||||
titleLabel.textPosition = .left
|
||||
titleLabel.typograpicalStyle = .BodySmall
|
||||
titleLabel.text = updatedLabelText
|
||||
titleLabel.attributes = attributes
|
||||
titleLabel.surface = surface
|
||||
@ -324,8 +360,6 @@ open class EntryField: Control, Accessable {
|
||||
|
||||
open func updateErrorLabel(){
|
||||
if showError, let errorText {
|
||||
errorLabel.textPosition = .left
|
||||
errorLabel.typograpicalStyle = .BodySmall
|
||||
errorLabel.text = errorText
|
||||
errorLabel.surface = surface
|
||||
errorLabel.disabled = disabled
|
||||
@ -338,8 +372,6 @@ open class EntryField: Control, Accessable {
|
||||
open func updateHelperLabel(){
|
||||
//set the helper label position
|
||||
if let helperText {
|
||||
helperLabel.textPosition = .left
|
||||
helperLabel.typograpicalStyle = .BodySmall
|
||||
helperLabel.text = helperText
|
||||
helperLabel.surface = surface
|
||||
helperLabel.disabled = disabled
|
||||
|
||||
@ -60,6 +60,8 @@ open class TextEntryFieldBase: EntryField {
|
||||
|
||||
private var successLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
$0.typograpicalStyle = .BodySmall
|
||||
}
|
||||
|
||||
internal var minWidthConstraint: NSLayoutConstraint?
|
||||
@ -80,6 +82,18 @@ open class TextEntryFieldBase: EntryField {
|
||||
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
successLabel.reset()
|
||||
successLabel.textPosition = .left
|
||||
successLabel.typograpicalStyle = .BodySmall
|
||||
|
||||
type = .text
|
||||
showSuccess = false
|
||||
successText = nil
|
||||
helperTextPlacement = .bottom
|
||||
}
|
||||
|
||||
open override func getContainer() -> UIView {
|
||||
containerStackView.addArrangedSubview(containerView)
|
||||
return containerStackView
|
||||
@ -126,8 +140,6 @@ open class TextEntryFieldBase: EntryField {
|
||||
successLabel.isHidden = true
|
||||
|
||||
} else if showSuccess, let successText {
|
||||
successLabel.textPosition = .left
|
||||
successLabel.typograpicalStyle = .BodySmall
|
||||
successLabel.text = successText
|
||||
successLabel.surface = surface
|
||||
successLabel.disabled = disabled
|
||||
|
||||
@ -58,32 +58,28 @@ open class ToggleBase: Control, Accessable, DataTrackable, BinaryColorable {
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var stackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .horizontal
|
||||
$0.distribution = .fill
|
||||
}
|
||||
}()
|
||||
private var stackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .horizontal
|
||||
$0.distribution = .fill
|
||||
}
|
||||
|
||||
private var label = Label()
|
||||
private var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
}
|
||||
|
||||
private var toggleView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}()
|
||||
|
||||
private var knobView: UIView = {
|
||||
return UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.backgroundColor = .white
|
||||
}
|
||||
}()
|
||||
private var toggleView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
private var knobView = UIView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.backgroundColor = .white
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
@ -298,6 +294,20 @@ open class ToggleBase: Control, Accessable, DataTrackable, BinaryColorable {
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
label.reset()
|
||||
isSelected = false
|
||||
isOn = false
|
||||
|
||||
isAnimated = true
|
||||
showText = false
|
||||
onText = "On"
|
||||
offText = "Off"
|
||||
textSize = .small
|
||||
textWeight = .regular
|
||||
textPosition = .left
|
||||
inputId = nil
|
||||
value = nil
|
||||
|
||||
toggleView.backgroundColor = toggleColorConfiguration.getColor(self)
|
||||
knobView.backgroundColor = knobColorConfiguration.getColor(self)
|
||||
setAccessibilityLabel()
|
||||
|
||||
@ -261,3 +261,23 @@ extension TypographicalStyle {
|
||||
}
|
||||
}
|
||||
|
||||
extension TypographicalStyle {
|
||||
public static func style(for fontName: String, size: CGFloat) -> TypographicalStyle? {
|
||||
//filter all styles by fontName
|
||||
let styles = allCases.filter{$0.fontFace.fontName == fontName }.sorted { lhs, rhs in lhs.pointSize < rhs.pointSize }
|
||||
|
||||
//if there are no styles then return nil
|
||||
guard styles.count > 0 else { return nil }
|
||||
|
||||
//if there is an exact match on a style with this pointSize then return it
|
||||
if let style = styles.first(where: {$0.pointSize == size }) {
|
||||
return style
|
||||
|
||||
} else if let largerIndex = styles.firstIndex(where: { $0.pointSize > size}) { //find the closet one to pointSize
|
||||
return styles[max(largerIndex - 1, 0)]
|
||||
|
||||
} else { //return the last style
|
||||
return styles.last!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user