diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 03aa3d87..089a1176 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -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 = ""; }; EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = ""; }; EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroup.swift; sourceTree = ""; }; + EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyLabelAttribute.swift; sourceTree = ""; }; EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageLabelAttribute.swift; sourceTree = ""; }; EAA5EEB628ECC03A003B3210 /* ToolTipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolTipLabelAttribute.swift; sourceTree = ""; }; EAA5EEB828ECD24B003B3210 /* Icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Icons.xcassets; sourceTree = ""; }; @@ -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 */, diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 0f7a2631..12e8fba4 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -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 - } + } } diff --git a/VDS/Classes/SelectorGroupHandlerBase.swift b/VDS/Classes/SelectorGroupHandlerBase.swift index 27c56353..acae21c5 100644 --- a/VDS/Classes/SelectorGroupHandlerBase.swift +++ b/VDS/Classes/SelectorGroupHandlerBase.swift @@ -43,6 +43,11 @@ public class SelectorGroupHandlerBase: Control { self?.sendActions(for: .valueChanged) } } + + public override func reset() { + super.reset() + selectorViews.forEach{ $0.reset() } + } } public class SelectorGroupSelectedHandlerBase: SelectorGroupHandlerBase{ diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index d0550acf..288ebf9b 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -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 diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index b4eedd81..d1287c2e 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -83,7 +83,10 @@ open class TextLink: Control { open override func reset() { super.reset() + label.reset() size = .large + text = nil + accessibilityCustomActions = [] accessibilityTraits = .staticText } diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index 7be3a156..5e6b5357 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -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 } diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 303d7f81..3a515eb4 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -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() } diff --git a/VDS/Components/Label/Attributes/AnyLabelAttribute.swift b/VDS/Components/Label/Attributes/AnyLabelAttribute.swift new file mode 100644 index 00000000..b914c912 --- /dev/null +++ b/VDS/Components/Label/Attributes/AnyLabelAttribute.swift @@ -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) + } +} diff --git a/VDS/Components/Label/Attributes/ColorLabelAttribute.swift b/VDS/Components/Label/Attributes/ColorLabelAttribute.swift index 8d70296d..e266f15f 100644 --- a/VDS/Components/Label/Attributes/ColorLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/ColorLabelAttribute.swift @@ -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) } } diff --git a/VDS/Components/Label/Attributes/FontLabelAttribute.swift b/VDS/Components/Label/Attributes/FontLabelAttribute.swift index 6456b76c..a1fc2ff2 100644 --- a/VDS/Components/Label/Attributes/FontLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/FontLabelAttribute.swift @@ -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) + } + } + } diff --git a/VDS/Components/Label/Attributes/LabelAttributeModel.swift b/VDS/Components/Label/Attributes/LabelAttributeModel.swift index c3209f68..7196a346 100644 --- a/VDS/Components/Label/Attributes/LabelAttributeModel.swift +++ b/VDS/Components/Label/Attributes/LabelAttributeModel.swift @@ -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) + } } diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 449c9c80..2b195de8 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -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) diff --git a/VDS/Components/RadioBox/RadioBox.swift b/VDS/Components/RadioBox/RadioBox.swift index e384fc35..d9245790 100644 --- a/VDS/Components/RadioBox/RadioBox.swift +++ b/VDS/Components/RadioBox/RadioBox.swift @@ -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() } diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index e46a4e8c..f52f2a09 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -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 diff --git a/VDS/Components/RadioSwatch/RadioSwatch.swift b/VDS/Components/RadioSwatch/RadioSwatch.swift index 0b39fd4a..520262d1 100644 --- a/VDS/Components/RadioSwatch/RadioSwatch.swift +++ b/VDS/Components/RadioSwatch/RadioSwatch.swift @@ -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() } diff --git a/VDS/Components/TextFields/EntryField/EntryField.swift b/VDS/Components/TextFields/EntryField/EntryField.swift index 65c1533f..3d8cfce0 100644 --- a/VDS/Components/TextFields/EntryField/EntryField.swift +++ b/VDS/Components/TextFields/EntryField/EntryField.swift @@ -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 diff --git a/VDS/Components/TextFields/TextEntryField/TextEntryField.swift b/VDS/Components/TextFields/TextEntryField/TextEntryField.swift index f64e27e9..c0eee646 100644 --- a/VDS/Components/TextFields/TextEntryField/TextEntryField.swift +++ b/VDS/Components/TextFields/TextEntryField/TextEntryField.swift @@ -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 diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 5a525a05..0694d0fb 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -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() diff --git a/VDS/Typography/Typography.swift b/VDS/Typography/Typography.swift index e8b8c2ba..86629d91 100644 --- a/VDS/Typography/Typography.swift +++ b/VDS/Typography/Typography.swift @@ -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! + } + } +}