Merge branch 'develop' into feature/monarch

This commit is contained in:
Matt Bruce 2024-05-07 14:12:09 -05:00
commit fa35654ebe
26 changed files with 381 additions and 68 deletions

View File

@ -140,6 +140,7 @@
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; }; EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; };
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; }; EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; };
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFEB632A26473700C4C106 /* NSAttributedString.swift */; }; EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFEB632A26473700C4C106 /* NSAttributedString.swift */; };
EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */; };
EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */; }; EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */; };
EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */; }; EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */; };
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; }; EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; };
@ -336,6 +337,7 @@
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; }; EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; };
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; }; EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = "<group>"; }; EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = "<group>"; };
EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTextColor.swift; sourceTree = "<group>"; };
EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; }; EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; }; EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; }; EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
@ -771,12 +773,13 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EA5E30522950DDA60082B959 /* TitleLockup.swift */, EA5E30522950DDA60082B959 /* TitleLockup.swift */,
EAEEECAC2B1FC1A600531FC2 /* TitleLockupChangeLog.txt */,
EA985BEF2968A93600F2FF2E /* TitleLockupEyebrowModel.swift */, EA985BEF2968A93600F2FF2E /* TitleLockupEyebrowModel.swift */,
EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */, EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */,
EA985BEB2968A91200F2FF2E /* TitleLockupTitleModel.swift */, EA985BEB2968A91200F2FF2E /* TitleLockupTitleModel.swift */,
EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */,
EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */, EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */,
EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */, EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */,
EAEEECAC2B1FC1A600531FC2 /* TitleLockupChangeLog.txt */,
); );
path = TitleLockup; path = TitleLockup;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1147,6 +1150,7 @@
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */, EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */,
EAC925842911C63100091998 /* Colorable.swift in Sources */, EAC925842911C63100091998 /* Colorable.swift in Sources */,
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */, 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */,
EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */,
EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAACB89A2B927108006A3869 /* Valuing.swift in Sources */,
EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */,
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,

View File

@ -210,6 +210,7 @@ open class BadgeIndicator: View {
/// The Container's height. /// The Container's height.
open var height: CGFloat? { didSet { setNeedsUpdate() } } open var height: CGFloat? { didSet { setNeedsUpdate() } }
open var accessibilityText: String? { didSet { setNeedsUpdate() } }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
@ -348,7 +349,9 @@ open class BadgeIndicator: View {
open override func updateAccessibility() { open override func updateAccessibility() {
super.updateAccessibility() super.updateAccessibility()
if kind == .numbered { if let accessibilityText {
accessibilityLabel = accessibilityText
} else if kind == .numbered {
accessibilityLabel = label.text accessibilityLabel = label.text
} else { } else {
accessibilityLabel = "Simple" accessibilityLabel = "Simple"

View File

@ -102,8 +102,6 @@ open class DropdownSelect: EntryFieldBase {
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
open override func setup() { open override func setup() {
super.setup() super.setup()
accessibilityLabel = "Dropdown Select"
// stackview for controls in EntryFieldBase.controlContainerView // stackview for controls in EntryFieldBase.controlContainerView
let controlStackView = UIStackView().with { let controlStackView = UIStackView().with {
@ -118,6 +116,10 @@ open class DropdownSelect: EntryFieldBase {
controlStackView.addArrangedSubview(inlineDisplayLabel) controlStackView.addArrangedSubview(inlineDisplayLabel)
controlStackView.addArrangedSubview(selectedOptionLabel) controlStackView.addArrangedSubview(selectedOptionLabel)
containerStackView.isAccessibilityElement = true
containerStackView.accessibilityLabel = "Dropdown Select"
inlineDisplayLabel.isAccessibilityElement = true
controlStackView.setCustomSpacing(0, after: dropdownField) controlStackView.setCustomSpacing(0, after: dropdownField)
controlStackView.setCustomSpacing(VDSLayout.space1X, after: inlineDisplayLabel) controlStackView.setCustomSpacing(VDSLayout.space1X, after: inlineDisplayLabel)
controlStackView.setCustomSpacing(VDSLayout.space3X, after: selectedOptionLabel) controlStackView.setCustomSpacing(VDSLayout.space3X, after: selectedOptionLabel)
@ -245,9 +247,41 @@ open class DropdownSelect: EntryFieldBase {
statusIcon.color = iconColorConfiguration.getColor(self) statusIcon.color = iconColorConfiguration.getColor(self)
} }
open override func updateAccessibility() {
super.updateAccessibility()
var selectedOption = selectedOptionLabel.text ?? ""
containerStackView.accessibilityLabel = "Dropdown Select, \(selectedOption) \(isReadOnly ? ", read only" : "")"
containerStackView.accessibilityHint = isReadOnly || !isEnabled ? "" : "Double tap to open."
}
open override var accessibilityElements: [Any]? {
get {
var elements = [Any]()
elements.append(contentsOf: [titleLabel, containerStackView])
if showError {
elements.append(statusIcon)
if let errorText, !errorText.isEmpty {
elements.append(errorLabel)
}
}
if let helperText, !helperText.isEmpty {
elements.append(helperLabel)
}
return elements
}
set { super.accessibilityElements = newValue }
}
@objc open func pickerDoneClicked() { @objc open func pickerDoneClicked() {
optionsPicker.isHidden = true optionsPicker.isHidden = true
dropdownField.resignFirstResponder() dropdownField.resignFirstResponder()
setNeedsUpdate()
UIAccessibility.post(notification: .layoutChanged, argument: containerStackView)
} }
} }
@ -258,6 +292,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource {
internal func launchPicker() { internal func launchPicker() {
if optionsPicker.isHidden { if optionsPicker.isHidden {
UIAccessibility.post(notification: .layoutChanged, argument: optionsPicker)
dropdownField.becomeFirstResponder() dropdownField.becomeFirstResponder()
} else { } else {
dropdownField.resignFirstResponder() dropdownField.resignFirstResponder()

View File

@ -544,6 +544,7 @@ open class ButtonIcon: Control, Changeable {
badgeIndicator.horizontalPadding = badgeIndicatorModel.horizontalPadding badgeIndicator.horizontalPadding = badgeIndicatorModel.horizontalPadding
badgeIndicator.hideDot = badgeIndicatorModel.hideDot badgeIndicator.hideDot = badgeIndicatorModel.hideDot
badgeIndicator.hideBorder = badgeIndicatorModel.hideBorder badgeIndicator.hideBorder = badgeIndicatorModel.hideBorder
badgeIndicator.accessibilityText = badgeIndicatorModel.accessibilityText
} }
private func updateExpandDirectionalConstraints() { private func updateExpandDirectionalConstraints() {

View File

@ -46,6 +46,9 @@ extension ButtonIcon {
/// Trailing Text height that will be used for the badge indicator. /// Trailing Text height that will be used for the badge indicator.
public var trailingText: String? public var trailingText: String?
/// Accessibliity Text
public var accessibilityText: String?
/// Dot Size that will be used for the badge indicator. /// Dot Size that will be used for the badge indicator.
public var dotSize: CGFloat? public var dotSize: CGFloat?
@ -61,7 +64,7 @@ extension ButtonIcon {
/// Hide Border that will be used for the badge indicator. /// Hide Border that will be used for the badge indicator.
public var hideBorder: Bool = false public var hideBorder: Bool = false
public init(kind: BadgeIndicator.Kind = .simple, fillColor: BadgeIndicator.FillColor = .red, expandDirection: ExpandDirection = .right, size: BadgeIndicator.Size = .xxlarge, maximumDigits: BadgeIndicator.MaximumDigits = .two, width: CGFloat? = nil, height: CGFloat? = nil, number: Int? = nil, leadingCharacter: String? = "", trailingText: String? = "", dotSize: CGFloat? = nil, verticalPadding: CGFloat? = nil, horizontalPadding: CGFloat? = nil, hideDot: Bool = false, hideBorder: Bool = false) { public init(kind: BadgeIndicator.Kind = .simple, fillColor: BadgeIndicator.FillColor = .red, expandDirection: ExpandDirection = .right, size: BadgeIndicator.Size = .xxlarge, maximumDigits: BadgeIndicator.MaximumDigits = .two, width: CGFloat? = nil, height: CGFloat? = nil, number: Int? = nil, leadingCharacter: String? = "", trailingText: String? = "", accessibilityText: String? = nil, dotSize: CGFloat? = nil, verticalPadding: CGFloat? = nil, horizontalPadding: CGFloat? = nil, hideDot: Bool = false, hideBorder: Bool = false) {
self.kind = kind self.kind = kind
self.fillColor = fillColor self.fillColor = fillColor
self.expandDirection = expandDirection self.expandDirection = expandDirection
@ -70,6 +73,7 @@ extension ButtonIcon {
self.width = width self.width = width
self.height = height self.height = height
self.number = number self.number = number
self.accessibilityText = accessibilityText
self.leadingCharacter = leadingCharacter self.leadingCharacter = leadingCharacter
self.trailingText = trailingText self.trailingText = trailingText
self.dotSize = dotSize self.dotSize = dotSize

View File

@ -77,7 +77,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
self.subscriber = subscriber self.subscriber = subscriber
self.surface = surface self.surface = surface
self.model = model self.model = model
self.accessibleText = accessibleText self.accessibleText = accessibleText ?? model.accessibleText
self.presenter = presenter self.presenter = presenter
//create the tooltip click event //create the tooltip click event

View File

@ -104,6 +104,7 @@ open class Notification: View {
open var typeIcon = Icon().with { open var typeIcon = Icon().with {
$0.name = .infoBold $0.name = .infoBold
$0.size = UIDevice.isIPad ? .medium : .small $0.size = UIDevice.isIPad ? .medium : .small
$0.accessibilityTraits.remove(.image)
} }
/// Icon used for the close. /// Icon used for the close.

View File

@ -207,7 +207,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
open override func setup() { open override func setup() {
super.setup() super.setup()
isAccessibilityElement = true isAccessibilityElement = false
addSubview(stackView) addSubview(stackView)
//create the wrapping view //create the wrapping view

View File

@ -148,7 +148,6 @@ open class InputField: EntryFieldBase {
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
open override func setup() { open override func setup() {
super.setup() super.setup()
isAccessibilityElement = false
minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0)
minWidthConstraint?.isActive = true minWidthConstraint?.isActive = true
@ -166,11 +165,12 @@ open class InputField: EntryFieldBase {
controlStackView.addArrangedSubview(textField) controlStackView.addArrangedSubview(textField)
textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField.heightAnchor.constraint(equalToConstant: 20).isActive = true
textField.delegate = self
textField textField
.textPublisher .textPublisher
.sink { [weak self] newText in .sink { [weak self] newText in
print("textPublisher newText: \(newText)") print("textPublisher newText: \(newText)")
self?.text = newText self?.process(text: newText)
self?.validate() self?.validate()
self?.sendActions(for: .valueChanged) self?.sendActions(for: .valueChanged)
}.store(in: &subscribers) }.store(in: &subscribers)
@ -281,6 +281,7 @@ open class InputField: EntryFieldBase {
var toolTipModel: Tooltip.TooltipModel? = tooltipModel var toolTipModel: Tooltip.TooltipModel? = tooltipModel
var isSecureTextEntry = false var isSecureTextEntry = false
var rules = [AnyRule<String>]() var rules = [AnyRule<String>]()
var placeholderText: String?
if self.isRequired { if self.isRequired {
let rule = RequiredRule() let rule = RequiredRule()
@ -327,6 +328,7 @@ open class InputField: EntryFieldBase {
case .date: case .date:
minWidth = 114.0 minWidth = 114.0
placeholderText = dateFormat.placeholderText
case .securityCode: case .securityCode:
minWidth = 88.0 minWidth = 88.0
@ -365,6 +367,9 @@ open class InputField: EntryFieldBase {
minWidthConstraint?.isActive = true minWidthConstraint?.isActive = true
} }
//placeholder
textField.placeholder = placeholderText
//tooltip //tooltip
tooltipModel = toolTipModel tooltipModel = toolTipModel
} }
@ -373,11 +378,29 @@ open class InputField: EntryFieldBase {
open override func updateAccessibility() { open override func updateAccessibility() {
super.updateAccessibility() super.updateAccessibility()
textField.accessibilityLabel = showError ? "error" : nil textField.accessibilityLabel = showError ? "error" : nil
if showError { }
accessibilityElements = [titleLabel, textField, statusIcon, errorLabel, helperLabel]
} else { open override var accessibilityElements: [Any]? {
accessibilityElements = [titleLabel, textField, helperLabel] get {
var elements = [Any]()
elements.append(contentsOf: [titleLabel, textField])
if showError {
elements.append(statusIcon)
if let errorText, !errorText.isEmpty {
elements.append(errorLabel)
}
} else if showSuccess, let successText, !successText.isEmpty {
elements.append(successLabel)
}
if let helperText, !helperText.isEmpty {
elements.append(helperLabel)
}
return elements
} }
set { super.accessibilityElements = newValue }
} }
open override var canBecomeFirstResponder: Bool { true } open override var canBecomeFirstResponder: Bool { true }
@ -404,6 +427,47 @@ open class InputField: EntryFieldBase {
open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } } open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } }
open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } }
//--------------------------------------------------
// MARK: - Date
//--------------------------------------------------
open var dateFormat: DateFormat = .mmddyy { didSet { setNeedsUpdate() } }
}
extension InputField: UITextFieldDelegate {
public func process(text changedText: String) {
var newText: String = changedText
switch fieldType {
case .date:
guard newText.count <= dateFormat.maxLength else { return }
let numericText = newText.compactMap { $0.isNumber ? $0 : nil }
var formattedText = ""
for (index, char) in numericText.enumerated() {
if (index == 2 || (index == 4 && (dateFormat != .mmyy))) && index < dateFormat.maxLength {
formattedText += "/"
}
formattedText.append(char)
}
newText = formattedText
default: break
}
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
switch fieldType {
case .date:
// Allow only numbers and limit the length of text.
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet) && ((textField.text?.count ?? 0) + string.count - range.length) <= dateFormat.maxLength
default:
return true
}
}
} }
extension InputField.FieldType { extension InputField.FieldType {
@ -425,3 +489,36 @@ extension InputField.FieldType {
} }
} }
} }
extension InputField {
public enum DateFormat: String, CaseIterable {
case mmyy
case mmddyy
case mmddyyyy
public var placeholderText: String {
switch self {
case .mmyy: "MM/YY"
case .mmddyy: "MM/DD/YY"
case .mmddyyyy: "MM/DD/YYYY"
}
}
public var formatString: String {
switch self {
case .mmyy: "MM/yy"
case .mmddyy: "MM/dd/yy"
case .mmddyyyy: "MM/dd/yyyy"
}
}
public var maxLength: Int {
switch self {
case .mmyy: 5
case .mmddyy: 8
case .mmddyyyy: 10
}
}
}
}

View File

@ -10,6 +10,25 @@ import UIKit
@objc(VDSTextField) @objc(VDSTextField)
open class TextField: UITextField { open class TextField: UITextField {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init() {
super.init(frame: .zero)
initialSetup()
}
public override init(frame: CGRect) {
super.init(frame: .zero)
initialSetup()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
initialSetup()
}
var horizontalPadding: CGFloat = 0 var horizontalPadding: CGFloat = 0
open override func textRect(forBounds bounds: CGRect) -> CGRect { open override func textRect(forBounds bounds: CGRect) -> CGRect {
@ -35,6 +54,25 @@ open class TextField: UITextField {
} }
} }
open func initialSetup() {
let doneToolbar: UIToolbar = UIToolbar()
doneToolbar.translatesAutoresizingMaskIntoConstraints = false
doneToolbar.barStyle = .default
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
done.accessibilityHint = "Double tap to finish editing."
doneToolbar.items = [flexSpace, done]
doneToolbar.sizeToFit()
inputAccessoryView = doneToolbar
}
@objc func doneButtonAction() {
// Resigns the first responder status when 'Done' is tapped
resignFirstResponder()
}
open override func becomeFirstResponder() -> Bool { open override func becomeFirstResponder() -> Bool {
let success = super.becomeFirstResponder() let success = super.becomeFirstResponder()
if isSecureTextEntry, let text { if isSecureTextEntry, let text {

View File

@ -161,7 +161,6 @@ open class TextArea: EntryFieldBase {
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
open override func setup() { open override func setup() {
super.setup() super.setup()
isAccessibilityElement = false
containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset))
minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width)
minWidthConstraint?.isActive = true minWidthConstraint?.isActive = true
@ -264,13 +263,31 @@ open class TextArea: EntryFieldBase {
open override func updateAccessibility() { open override func updateAccessibility() {
super.updateAccessibility() super.updateAccessibility()
textView.accessibilityLabel = showError ? "error" : nil textView.accessibilityLabel = showError ? "error" : nil
if showError {
accessibilityElements = [titleLabel, textView, statusIcon, errorLabel, helperLabel]
} else {
accessibilityElements = [titleLabel, textView, helperLabel]
}
} }
open override var accessibilityElements: [Any]? {
get {
var elements = [Any]()
elements.append(contentsOf: [titleLabel, textView])
if showError {
elements.append(statusIcon)
if let errorText, !errorText.isEmpty {
elements.append(errorLabel)
}
}
if let helperText, !helperText.isEmpty {
elements.append(helperLabel)
}
return elements
}
set { super.accessibilityElements = newValue }
}
open override var canBecomeFirstResponder: Bool { true } open override var canBecomeFirstResponder: Bool { true }
open override func resignFirstResponder() -> Bool { open override func resignFirstResponder() -> Bool {

View File

@ -97,7 +97,6 @@ open class TextView: UITextView, ViewProtocol {
initialSetupPerformed = true initialSetupPerformed = true
backgroundColor = .clear backgroundColor = .clear
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
accessibilityCustomActions = []
setup() setup()
setNeedsUpdate() setNeedsUpdate()
} }
@ -106,8 +105,25 @@ open class TextView: UITextView, ViewProtocol {
open func setup() { open func setup() {
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
let doneToolbar: UIToolbar = UIToolbar()
doneToolbar.translatesAutoresizingMaskIntoConstraints = false
doneToolbar.barStyle = .default
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
done.accessibilityHint = "Double tap to finish editing."
doneToolbar.items = [flexSpace, done]
doneToolbar.sizeToFit()
inputAccessoryView = doneToolbar
} }
@objc func doneButtonAction() {
// Resigns the first responder status when 'Done' is tapped
resignFirstResponder()
}
open func updateView() { open func updateView() {
updateLabel() updateLabel()
} }
@ -118,7 +134,6 @@ open class TextView: UITextView, ViewProtocol {
shouldUpdateView = false shouldUpdateView = false
surface = .light surface = .light
text = nil text = nil
accessibilityCustomActions = []
shouldUpdateView = true shouldUpdateView = true
setNeedsUpdate() setNeedsUpdate()
} }

View File

@ -69,7 +69,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
case secondary case secondary
case white case white
case black case black
case custom(String) case custom(UIColor)
private var reflectedValue: String { String(reflecting: self) } private var reflectedValue: String { String(reflecting: self) }
@ -81,7 +81,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
/// Enum used to describe the background effect choices used for this component. /// Enum used to describe the background effect choices used for this component.
public enum BackgroundEffect { public enum BackgroundEffect {
case transparency case transparency
case gradient(String, String) case gradient(UIColor, UIColor)
case none case none
} }
@ -128,7 +128,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } } open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } }
/// Sets the background color for the component. /// Sets the background color for the component.
open var color: BackgroundColor = .secondary { didSet { setNeedsUpdate() } } open var color: BackgroundColor? { didSet { setNeedsUpdate() } }
/// Sets the background effect for the component. /// Sets the background effect for the component.
open var backgroundEffect: BackgroundEffect = .none { didSet { setNeedsUpdate() } } open var backgroundEffect: BackgroundEffect = .none { didSet { setNeedsUpdate() } }
@ -188,14 +188,14 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
// MARK: - Configuration // MARK: - Configuration
//-------------------------------------------------- //--------------------------------------------------
private let cornerRadius = VDSFormControls.borderRadius * 2 private let cornerRadius = VDSFormControls.borderRadius * 2
private var backgroundColorConfiguration = BackgroundColorConfiguration() internal var backgroundColorConfiguration = BackgroundColorConfiguration()
private let dropShadowConfiguration = DropShadowConfiguration().with { private let dropShadowConfiguration = DropShadowConfiguration().with {
$0.shadowColorConfiguration = SurfaceColorConfiguration().with { $0.shadowColorConfiguration = SurfaceColorConfiguration().with {
$0.lightColor = VDSColor.elementsPrimaryOnlight $0.lightColor = VDSColor.elementsPrimaryOnlight
}.eraseToAnyColorable() }.eraseToAnyColorable()
$0.shadowOffsetConfiguration = .init(.init(width: 0, height: 6), .zero) $0.shadowOffsetConfiguration = .init(.init(width: 0, height: 6), .zero)
$0.shadowRadiusConfiguration = .init(3.0, 0.0) $0.shadowRadiusConfiguration = .init(8.0, 0.0)
$0.shadowOpacityConfiguration = .init(0.01, 0.0) $0.shadowOpacityConfiguration = .init(0.1, 0.0)
} }
private var borderColorConfiguration = SurfaceColorConfiguration().with { private var borderColorConfiguration = SurfaceColorConfiguration().with {
@ -329,7 +329,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
} }
applyBackgroundEffects() applyBackgroundEffects()
if showDropShadow, surface == .light { if showDropShadow, surface == .light {
addDropShadow(dropShadowConfiguration) addDropShadow(dropShadowConfiguration)
} else { } else {
@ -395,7 +395,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
removeGradientLayer() removeGradientLayer()
case .gradient(let firstColor, let secondColor): case .gradient(let firstColor, let secondColor):
alphaConfiguration = 1.0 alphaConfiguration = 1.0
addGradientLayer(with: UIColor(hexString: firstColor), secondColor: UIColor(hexString: secondColor)) addGradientLayer(with: firstColor, secondColor: secondColor)
backgroundImageView.isHidden = true backgroundImageView.isHidden = true
backgroundImageView.alpha = 1.0 backgroundImageView.alpha = 1.0
case .none: case .none:
@ -461,17 +461,22 @@ extension TileContainerBase {
required init() { } required init() { }
func getColor(_ object: ObjectType) -> UIColor { func getColor(_ object: ObjectType) -> UIColor {
switch object.color { guard let color = object.color else {
let config = object.surface == .light ? blackColorConfig : whiteColorConfig
return config.getColor(object.surface)
}
switch color {
case .primary: case .primary:
primaryColorConfig.getColor(object.surface) return primaryColorConfig.getColor(object.surface)
case .secondary: case .secondary:
secondaryColorConfig.getColor(object.surface) return secondaryColorConfig.getColor(object.surface)
case .white: case .white:
whiteColorConfig.getColor(object.surface) return whiteColorConfig.getColor(object.surface)
case .black: case .black:
blackColorConfig.getColor(object.surface) return blackColorConfig.getColor(object.surface)
case .custom(let hexCode): case .custom(let color):
UIColor(hexString: hexCode) return color
} }
} }
} }

View File

@ -102,6 +102,10 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
$0.backgroundColor = .clear $0.backgroundColor = .clear
} }
private var backgroundColorSurface: Surface {
backgroundColorConfiguration.getColor(self).surface
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Public Properties // MARK: - Public Properties
//-------------------------------------------------- //--------------------------------------------------
@ -444,7 +448,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
badge.text = badgeModel.text badge.text = badgeModel.text
badge.fillColor = badgeModel.fillColor badge.fillColor = badgeModel.fillColor
badge.numberOfLines = badgeModel.numberOfLines badge.numberOfLines = badgeModel.numberOfLines
badge.surface = badgeModel.surface badge.surface = backgroundColorSurface
badge.maxWidth = badgeModel.maxWidth badge.maxWidth = badgeModel.maxWidth
badgeLabelHeightGreaterThanConstraint?.constant = badge.label.minimumLineHeight badgeLabelHeightGreaterThanConstraint?.constant = badge.label.minimumLineHeight
if badgeContainerView.superview == nil { if badgeContainerView.superview == nil {
@ -474,7 +478,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
if showTitleLockup { if showTitleLockup {
//flip the surface for the titleLockup //flip the surface for the titleLockup
titleLockup.surface = color == .black ? Surface.dark : Surface.light titleLockup.surface = backgroundColorSurface
//titleLockup //titleLockup
if let textWidth { if let textWidth {
@ -529,14 +533,14 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
if let descriptiveIconModel { if let descriptiveIconModel {
descriptiveIcon.name = descriptiveIconModel.name descriptiveIcon.name = descriptiveIconModel.name
descriptiveIcon.size = descriptiveIconModel.size descriptiveIcon.size = descriptiveIconModel.size
descriptiveIcon.surface = descriptiveIconModel.surface descriptiveIcon.surface = backgroundColorSurface
descriptiveIcon.accessibilityLabel = descriptiveIconModel.accessibleText descriptiveIcon.accessibilityLabel = descriptiveIconModel.accessibleText
showIconContainerView = true showIconContainerView = true
} }
if let directionalIconModel { if let directionalIconModel {
directionalIcon.size = directionalIconModel.size directionalIcon.size = directionalIconModel.size
directionalIcon.surface = directionalIconModel.surface directionalIcon.surface = backgroundColorSurface
directionalIcon.accessibilityLabel = "Right arrow" directionalIcon.accessibilityLabel = "Right arrow"
showIconContainerView = true showIconContainerView = true
} }

View File

@ -36,8 +36,8 @@ extension Tilelet {
public var textAttributes: [any LabelAttributeModel]? public var textAttributes: [any LabelAttributeModel]?
/// Text color that will be used for the subTitle label. /// Text color that will be used for the subTitle label.
public var textColor: Use = .primary public var textColor: TitleLockup.TextColor
/// LineBreakMode used in Badge label. /// LineBreakMode used in Badge label.
public var lineBreakMode: NSLineBreakMode public var lineBreakMode: NSLineBreakMode
@ -46,7 +46,7 @@ extension Tilelet {
//-------------------------------------------------- //--------------------------------------------------
public init(text: String, public init(text: String,
otherStandardStyle: OtherStandardStyle = .bodySmall, otherStandardStyle: OtherStandardStyle = .bodySmall,
textColor: Use = .primary, textColor: TitleLockup.TextColor = .primary,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
lineBreakMode: NSLineBreakMode = .byTruncatingTail) { lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
self.text = text self.text = text
@ -64,7 +64,8 @@ extension Tilelet {
TitleLockup.SubTitleModel(text: text, TitleLockup.SubTitleModel(text: text,
otherStandardStyle: otherStandardStyle.value, otherStandardStyle: otherStandardStyle.value,
textColor: textColor, textColor: textColor,
textAttributes: textAttributes, lineBreakMode: lineBreakMode) textAttributes: textAttributes,
lineBreakMode: lineBreakMode)
} }
} }
} }

View File

@ -32,6 +32,9 @@ extension Tilelet {
/// Text that will be used for the title label. /// Text that will be used for the title label.
public var text: String = "" public var text: String = ""
/// TextColor that will be used for the title label.
public var textColor: TitleLockup.TitleTextColor
/// Used in combination with standardStyle to set the textStyle that will be used for the title label. /// Used in combination with standardStyle to set the textStyle that will be used for the title label.
public var isBold: Bool = false public var isBold: Bool = false
/// Text attributes that will be used for the title label. /// Text attributes that will be used for the title label.
@ -47,11 +50,13 @@ extension Tilelet {
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
public init(text: String, public init(text: String,
textColor: TitleLockup.TitleTextColor = .primary,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
isBold: Bool = true, isBold: Bool = true,
standardStyle: StandardStyle = .titleSmall, standardStyle: StandardStyle = .titleSmall,
lineBreakMode: NSLineBreakMode = .byTruncatingTail) { lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
self.text = text self.text = text
self.textColor = textColor
self.textAttributes = textAttributes self.textAttributes = textAttributes
self.standardStyle = standardStyle self.standardStyle = standardStyle
self.isBold = isBold self.isBold = isBold
@ -64,8 +69,11 @@ extension Tilelet {
/// Converts this type of model to a TitleLockup.TitleModel. /// Converts this type of model to a TitleLockup.TitleModel.
public func toTitleLockupTitleModel() -> TitleLockup.TitleModel { public func toTitleLockupTitleModel() -> TitleLockup.TitleModel {
TitleLockup.TitleModel(text: text, TitleLockup.TitleModel(text: text,
textColor: textColor,
textAttributes: textAttributes, textAttributes: textAttributes,
isBold: isBold, standardStyle: standardStyle.value, lineBreakMode: lineBreakMode) isBold: isBold,
standardStyle: standardStyle.value,
lineBreakMode: lineBreakMode)
} }
} }
} }

View File

@ -18,6 +18,9 @@ extension Tilelet {
/// Text that will be used for the eyebrow label. /// Text that will be used for the eyebrow label.
public var text: String = "" public var text: String = ""
/// Text color that will be used for the eyebrow label
public var textColor: TitleLockup.TextColor
/// Used in combination with standardStyle to set the textStyle that will be used for the eyebrow label. /// Used in combination with standardStyle to set the textStyle that will be used for the eyebrow label.
public var isBold: Bool = false public var isBold: Bool = false
/// Text attributes that will be used for the eyebrow label. /// Text attributes that will be used for the eyebrow label.
@ -33,11 +36,13 @@ extension Tilelet {
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
public init(text: String, public init(text: String,
textColor: TitleLockup.TextColor = .primary,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
isBold: Bool = true, isBold: Bool = true,
standardStyle: Tilelet.SubTitleModel.OtherStandardStyle = .bodySmall, standardStyle: Tilelet.SubTitleModel.OtherStandardStyle = .bodySmall,
lineBreakMode: NSLineBreakMode = .byTruncatingTail) { lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
self.text = text self.text = text
self.textColor = textColor
self.textAttributes = textAttributes self.textAttributes = textAttributes
self.standardStyle = standardStyle self.standardStyle = standardStyle
self.isBold = isBold self.isBold = isBold
@ -49,7 +54,11 @@ extension Tilelet {
//-------------------------------------------------- //--------------------------------------------------
/// Converts this type of model to a TitleLockup.TitleModel. /// Converts this type of model to a TitleLockup.TitleModel.
public func toTitleLockupEyebrowModel() -> TitleLockup.EyebrowModel { public func toTitleLockupEyebrowModel() -> TitleLockup.EyebrowModel {
TitleLockup.EyebrowModel(text: text, isBold: isBold, standardStyle: standardStyle.value, textAttributes: textAttributes) TitleLockup.EyebrowModel(text: text,
textColor: textColor,
isBold: isBold,
standardStyle: standardStyle.value,
textAttributes: textAttributes)
} }
} }
} }

View File

@ -258,22 +258,10 @@ open class TitleLockup: View {
bottomSpacing: VDSLayout.space6X) bottomSpacing: VDSLayout.space6X)
]), ]),
]) ])
private var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable()
private var textColorPrimaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark).eraseToAnyColorable()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Overrides // MARK: - Overrides
//-------------------------------------------------- //--------------------------------------------------
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
open override func setup() {
super.setup()
titleLabel.textColorConfiguration = textColorPrimaryConfiguration
}
open override func updateAccessibility() { open override func updateAccessibility() {
super.updateAccessibility() super.updateAccessibility()
var elements = [Any]() var elements = [Any]()
@ -330,6 +318,7 @@ open class TitleLockup: View {
if let eyebrowModel, !eyebrowModel.text.isEmpty { if let eyebrowModel, !eyebrowModel.text.isEmpty {
eyebrowLabel.textAlignment = allLabelsTextAlignment eyebrowLabel.textAlignment = allLabelsTextAlignment
eyebrowLabel.text = eyebrowModel.text eyebrowLabel.text = eyebrowModel.text
eyebrowLabel.textColorConfiguration = eyebrowModel.textColor.configuration
eyebrowLabel.attributes = eyebrowModel.textAttributes eyebrowLabel.attributes = eyebrowModel.textAttributes
eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines
eyebrowLabel.surface = surface eyebrowLabel.surface = surface
@ -339,15 +328,12 @@ open class TitleLockup: View {
//When uniform size is true and the title is bold, //When uniform size is true and the title is bold,
//the eyebrow is always regular weight and the secondary color. //the eyebrow is always regular weight and the secondary color.
eyebrowLabel.textStyle = otherStandardStyle.value.regular eyebrowLabel.textStyle = otherStandardStyle.value.regular
eyebrowLabel.textColorConfiguration = textColorSecondaryConfiguration
} else { } else {
//When uniform size is true and the title is regular weight //When uniform size is true and the title is regular weight
//the eyebrow is always bold and uses the primary color. //the eyebrow is always bold and uses the primary color.
eyebrowLabel.textStyle = otherStandardStyle.value.bold eyebrowLabel.textStyle = otherStandardStyle.value.bold
eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration
} }
} else { } else {
eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration
eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular
} }
addSubview(eyebrowLabel) addSubview(eyebrowLabel)
@ -363,6 +349,7 @@ open class TitleLockup: View {
if let titleModel, !titleModel.text.isEmpty { if let titleModel, !titleModel.text.isEmpty {
titleLabel.textAlignment = allLabelsTextAlignment titleLabel.textAlignment = allLabelsTextAlignment
titleLabel.textStyle = titleModel.textStyle titleLabel.textStyle = titleModel.textStyle
titleLabel.textColorConfiguration = titleModel.textColor.configuration
titleLabel.text = titleModel.text titleLabel.text = titleModel.text
titleLabel.attributes = titleModel.textAttributes titleLabel.attributes = titleModel.textAttributes
titleLabel.numberOfLines = titleModel.numberOfLines titleLabel.numberOfLines = titleModel.numberOfLines
@ -381,7 +368,7 @@ open class TitleLockup: View {
if let subTitleModel, !subTitleModel.text.isEmpty { if let subTitleModel, !subTitleModel.text.isEmpty {
subTitleLabel.textAlignment = allLabelsTextAlignment subTitleLabel.textAlignment = allLabelsTextAlignment
subTitleLabel.textStyle = otherStandardStyle.value.regular subTitleLabel.textStyle = otherStandardStyle.value.regular
subTitleLabel.textColorConfiguration = subTitleModel.textColor == .secondary ? textColorSecondaryConfiguration : textColorPrimaryConfiguration subTitleLabel.textColorConfiguration = subTitleModel.textColor.configuration
subTitleLabel.text = subTitleModel.text subTitleLabel.text = subTitleModel.text
subTitleLabel.attributes = subTitleModel.textAttributes subTitleLabel.attributes = subTitleModel.textAttributes
subTitleLabel.numberOfLines = subTitleModel.numberOfLines subTitleLabel.numberOfLines = subTitleModel.numberOfLines

View File

@ -13,6 +13,9 @@ extension TitleLockup {
/// Text that will be used for the eyebrow label. /// Text that will be used for the eyebrow label.
public var text: String public var text: String
/// Text color that will be used for the eyebrow label
public var textColor: TextColor
/// Used in combination with standardStyle to set the textStyle that will be used for the eyebrow label. /// Used in combination with standardStyle to set the textStyle that will be used for the eyebrow label.
public var isBold: Bool public var isBold: Bool
@ -26,11 +29,13 @@ extension TitleLockup {
public var numberOfLines: Int public var numberOfLines: Int
public init(text: String, public init(text: String,
textColor: TextColor = .primary,
isBold: Bool = true, isBold: Bool = true,
standardStyle: OtherStandardStyle = .bodyLarge, standardStyle: OtherStandardStyle = .bodyLarge,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
numberOfLines: Int = 0) { numberOfLines: Int = 0) {
self.text = text self.text = text
self.textColor = textColor
self.isBold = isBold self.isBold = isBold
self.standardStyle = standardStyle self.standardStyle = standardStyle
self.textAttributes = textAttributes self.textAttributes = textAttributes
@ -41,3 +46,4 @@ extension TitleLockup {
public var textStyle: TextStyle { isBold ? standardStyle.value.bold : standardStyle.value.regular } public var textStyle: TextStyle { isBold ? standardStyle.value.bold : standardStyle.value.regular }
} }
} }

View File

@ -18,7 +18,7 @@ extension TitleLockup {
public var otherStandardStyle: OtherStandardStyle public var otherStandardStyle: OtherStandardStyle
/// Text color used in the subtitle label. /// Text color used in the subtitle label.
public var textColor: Use public var textColor: TextColor
/// Array of LabelAttributeModel objects used in rendering the text in the subtitle label. /// Array of LabelAttributeModel objects used in rendering the text in the subtitle label.
public var textAttributes: [any LabelAttributeModel]? public var textAttributes: [any LabelAttributeModel]?
@ -31,7 +31,7 @@ extension TitleLockup {
public init(text: String, public init(text: String,
otherStandardStyle: OtherStandardStyle = .bodyLarge, otherStandardStyle: OtherStandardStyle = .bodyLarge,
textColor: Use = .primary, textColor: TextColor = .primary,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
numberOfLines: Int = 0, numberOfLines: Int = 0,
lineBreakMode: NSLineBreakMode = .byWordWrapping) { lineBreakMode: NSLineBreakMode = .byWordWrapping) {

View File

@ -0,0 +1,59 @@
//
// TitleLockupTextColor.swift
// VDS
//
// Created by Matt Bruce on 5/6/24.
//
import Foundation
import VDSTokens
import UIKit
extension TitleLockup {
private static var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable()
private static var textColorPrimaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark).eraseToAnyColorable()
public enum TextColor: Equatable {
case primary
case secondary
case custom(UIColor, UIColor)
private var reflectedValue: String { String(reflecting: self) }
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.reflectedValue == rhs.reflectedValue
}
public var configuration: AnyColorable {
switch self {
case .primary:
TitleLockup.textColorPrimaryConfiguration
case .secondary:
TitleLockup.textColorSecondaryConfiguration
case .custom(let lightColor, let darkColor):
SurfaceColorConfiguration(lightColor, darkColor).eraseToAnyColorable()
}
}
}
public enum TitleTextColor: Equatable {
case primary
case custom(UIColor, UIColor)
private var reflectedValue: String { String(reflecting: self) }
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.reflectedValue == rhs.reflectedValue
}
public var configuration: AnyColorable {
switch self {
case .primary:
TitleLockup.textColorPrimaryConfiguration
case .custom(let lightColor, let darkColor):
SurfaceColorConfiguration(lightColor, darkColor).eraseToAnyColorable()
}
}
}
}

View File

@ -14,7 +14,10 @@ extension TitleLockup {
/// Text that will be used for the title label. /// Text that will be used for the title label.
public var text: String public var text: String
/// Array of LabelAttributeModel objects used in rendering the text. /// Text color that will be used for the eyebrow label
public var textColor: TitleTextColor
/// Array of LabelAttributeModel objects used in rendering the text.
public var textAttributes: [any LabelAttributeModel]? public var textAttributes: [any LabelAttributeModel]?
/// Used in combination with standardStyle to set the textStyle that will be used for the title label. /// Used in combination with standardStyle to set the textStyle that will be used for the title label.
@ -30,12 +33,14 @@ extension TitleLockup {
public var lineBreakMode: NSLineBreakMode public var lineBreakMode: NSLineBreakMode
public init(text: String, public init(text: String,
textColor: TitleTextColor = .primary,
textAttributes: [any LabelAttributeModel]? = nil, textAttributes: [any LabelAttributeModel]? = nil,
isBold: Bool = true, isBold: Bool = true,
standardStyle: TitleStandardStyle = .featureXSmall, standardStyle: TitleStandardStyle = .featureXSmall,
numberOfLines: Int = 0, numberOfLines: Int = 0,
lineBreakMode: NSLineBreakMode = .byTruncatingTail) { lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
self.text = text self.text = text
self.textColor = textColor
self.isBold = isBold self.isBold = isBold
self.textAttributes = textAttributes self.textAttributes = textAttributes
self.standardStyle = standardStyle self.standardStyle = standardStyle

View File

@ -48,7 +48,6 @@ open class TooltipDialog: View, UIScrollViewDelegate {
lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with { lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with {
$0.accessibilityLabel = "Modal" $0.accessibilityLabel = "Modal"
$0.accessibilityFrameInContainerSpace = .init(origin: .zero, size: .init(width: fullWidth, height: VDSLayout.space1X))
} }
//-------------------------------------------------- //--------------------------------------------------
@ -222,7 +221,8 @@ open class TooltipDialog: View, UIScrollViewDelegate {
super.updateAccessibility() super.updateAccessibility()
primaryAccessibilityElement.accessibilityHint = "Double tap on the \(tooltipModel.closeButtonText) button to close." primaryAccessibilityElement.accessibilityHint = "Double tap on the \(tooltipModel.closeButtonText) button to close."
primaryAccessibilityElement.accessibilityFrameInContainerSpace = .init(origin: .zero, size: frame.size)
var elements: [Any] = [primaryAccessibilityElement] var elements: [Any] = [primaryAccessibilityElement]
contentStackView.arrangedSubviews.forEach{ elements.append($0) } contentStackView.arrangedSubviews.forEach{ elements.append($0) }
elements.append(closeButton) elements.append(closeButton)

View File

@ -17,16 +17,19 @@ extension Tooltip {
public var title: String? public var title: String?
public var content: String? public var content: String?
public var contentView: UIView? public var contentView: UIView?
public var accessibleText: String?
public var contentViewAlignment: UIStackView.Alignment? public var contentViewAlignment: UIStackView.Alignment?
public init(closeButtonText: String = "Close", public init(closeButtonText: String = "Close",
title: String? = nil, title: String? = nil,
content: String? = nil, content: String? = nil,
contentView: UIView? = nil, contentView: UIView? = nil,
accessibleText: String? = "Tooltip",
contentViewAlignment: UIStackView.Alignment = .leading) { contentViewAlignment: UIStackView.Alignment = .leading) {
self.closeButtonText = closeButtonText self.closeButtonText = closeButtonText
self.title = title self.title = title
self.content = content self.content = content
self.contentView = contentView self.contentView = contentView
self.accessibleText = accessibleText
self.contentViewAlignment = contentViewAlignment self.contentViewAlignment = contentViewAlignment
} }
} }

View File

@ -176,4 +176,10 @@ extension UIColor {
guard let found else { return nil} guard let found else { return nil}
return found return found
} }
public var surface: Surface {
var greyScale: CGFloat = 0
getWhite(&greyScale, alpha: nil)
return greyScale < 0.5 ? .dark : .light
}
} }

View File

@ -1,3 +1,8 @@
1.0.62
----------------
- CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon.
- CXTDT-553663 - DropdownSelect - Accessibility - 5 issues
1.0.61 1.0.61
---------------- ----------------
- CXTDT-552068 - Text Area - Text padding - CXTDT-552068 - Text Area - Text padding