From 649ff1945df76ef144f7ba225b03625c4d8020c5 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 13:55:25 -0500 Subject: [PATCH 01/22] CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index bd4df763..b1010176 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -104,6 +104,7 @@ open class Notification: View { open var typeIcon = Icon().with { $0.name = .infoBold $0.size = UIDevice.isIPad ? .medium : .small + $0.accessibilityTraits.remove(.image) } /// Icon used for the close. From 3107c69dcb483ac767d83773e2955f40419a5998 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 13:56:03 -0500 Subject: [PATCH 02/22] release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 7cea34d5..cad514ec 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,7 @@ +1.0.62 +---------------- +- CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. + 1.0.61 ---------------- - CXTDT-552068 - Text Area - Text padding From 6518ffe5131c344091a89bddee5370eccf6a382b Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:26:39 -0500 Subject: [PATCH 03/22] CXTDT-553663 - DropdownSelect - Accessibility - 5 issues Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index e86b3792..80f94988 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -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. open override func setup() { super.setup() - - accessibilityLabel = "Dropdown Select" // stackview for controls in EntryFieldBase.controlContainerView let controlStackView = UIStackView().with { @@ -118,6 +116,10 @@ open class DropdownSelect: EntryFieldBase { controlStackView.addArrangedSubview(inlineDisplayLabel) controlStackView.addArrangedSubview(selectedOptionLabel) + containerStackView.isAccessibilityElement = true + containerStackView.accessibilityLabel = "Dropdown Select" + inlineDisplayLabel.isAccessibilityElement = true + controlStackView.setCustomSpacing(0, after: dropdownField) controlStackView.setCustomSpacing(VDSLayout.space1X, after: inlineDisplayLabel) controlStackView.setCustomSpacing(VDSLayout.space3X, after: selectedOptionLabel) @@ -245,9 +247,41 @@ open class DropdownSelect: EntryFieldBase { 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() { optionsPicker.isHidden = true dropdownField.resignFirstResponder() + setNeedsUpdate() + UIAccessibility.post(notification: .layoutChanged, argument: containerStackView) } } @@ -258,6 +292,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { internal func launchPicker() { if optionsPicker.isHidden { + UIAccessibility.post(notification: .layoutChanged, argument: optionsPicker) dropdownField.becomeFirstResponder() } else { dropdownField.resignFirstResponder() From b5b5c0d9e4c502bee297914971f22dae02f9dddc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:27:00 -0500 Subject: [PATCH 04/22] refactored accessibility elements Signed-off-by: Matt Bruce --- .../Attributes/TooltipLabelAttribute.swift | 2 +- .../TextFields/EntryFieldBase.swift | 2 +- .../TextFields/InputField/InputField.swift | 27 +++++++++++++---- .../TextFields/TextArea/TextArea.swift | 29 +++++++++++++++---- VDS/Components/Tooltip/TooltipModel.swift | 3 ++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 20666b10..6b03d103 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -77,7 +77,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable self.subscriber = subscriber self.surface = surface self.model = model - self.accessibleText = accessibleText + self.accessibleText = accessibleText ?? model.accessibleText self.presenter = presenter //create the tooltip click event diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 644a8de1..5c549564 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -207,7 +207,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open override func setup() { super.setup() - isAccessibilityElement = true + isAccessibilityElement = false addSubview(stackView) //create the wrapping view diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 640538fe..eb67c255 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -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. open override func setup() { super.setup() - isAccessibilityElement = false minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) minWidthConstraint?.isActive = true @@ -373,11 +372,29 @@ open class InputField: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() textField.accessibilityLabel = showError ? "error" : nil - if showError { - accessibilityElements = [titleLabel, textField, statusIcon, errorLabel, helperLabel] - } else { - accessibilityElements = [titleLabel, textField, helperLabel] + } + + open override var accessibilityElements: [Any]? { + 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 } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 7229c4a9..5ea944a3 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -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. open override func setup() { super.setup() - isAccessibilityElement = false containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true @@ -264,13 +263,31 @@ open class TextArea: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() 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 func resignFirstResponder() -> Bool { diff --git a/VDS/Components/Tooltip/TooltipModel.swift b/VDS/Components/Tooltip/TooltipModel.swift index ee690d74..461fda66 100644 --- a/VDS/Components/Tooltip/TooltipModel.swift +++ b/VDS/Components/Tooltip/TooltipModel.swift @@ -17,16 +17,19 @@ extension Tooltip { public var title: String? public var content: String? public var contentView: UIView? + public var accessibleText: String? public var contentViewAlignment: UIStackView.Alignment? public init(closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil, + accessibleText: String? = "Tooltip", contentViewAlignment: UIStackView.Alignment = .leading) { self.closeButtonText = closeButtonText self.title = title self.content = content self.contentView = contentView + self.accessibleText = accessibleText self.contentViewAlignment = contentViewAlignment } } From 3f899eb7c2e7e616a9dfbb33a77f88b2bb618313 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:27:35 -0500 Subject: [PATCH 05/22] updated release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index cad514ec..258951db 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,6 +1,7 @@ 1.0.62 ---------------- - CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. +- CXTDT-553663 - DropdownSelect - Accessibility - 5 issues 1.0.61 ---------------- From b6ace4039b4da414e9bb69535fed327ee2fa333c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:34:03 -0500 Subject: [PATCH 06/22] updated tooltip accessible main view Signed-off-by: Matt Bruce --- VDS/Components/Tooltip/TooltipDialog.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Tooltip/TooltipDialog.swift b/VDS/Components/Tooltip/TooltipDialog.swift index 9822baae..a9ee3714 100644 --- a/VDS/Components/Tooltip/TooltipDialog.swift +++ b/VDS/Components/Tooltip/TooltipDialog.swift @@ -48,7 +48,6 @@ open class TooltipDialog: View, UIScrollViewDelegate { lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with { $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() primaryAccessibilityElement.accessibilityHint = "Double tap on the \(tooltipModel.closeButtonText) button to close." - + primaryAccessibilityElement.accessibilityFrameInContainerSpace = .init(origin: .zero, size: frame.size) + var elements: [Any] = [primaryAccessibilityElement] contentStackView.arrangedSubviews.forEach{ elements.append($0) } elements.append(closeButton) From e2a23d63819129fb6a65e673d0ec5af6cb4555c9 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 09:24:30 -0500 Subject: [PATCH 07/22] added done button Signed-off-by: Matt Bruce --- .../TextFields/InputField/TextField.swift | 38 +++++++++++++++++++ .../TextFields/TextArea/TextView.swift | 19 +++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 14178020..9a96829e 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -10,6 +10,25 @@ import UIKit @objc(VDSTextField) 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 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 { let success = super.becomeFirstResponder() if isSecureTextEntry, let text { diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index c35b4a80..efe8164b 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -97,7 +97,6 @@ open class TextView: UITextView, ViewProtocol { initialSetupPerformed = true backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false - accessibilityCustomActions = [] setup() setNeedsUpdate() } @@ -106,8 +105,25 @@ open class TextView: UITextView, ViewProtocol { open func setup() { 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() { updateLabel() } @@ -118,7 +134,6 @@ open class TextView: UITextView, ViewProtocol { shouldUpdateView = false surface = .light text = nil - accessibilityCustomActions = [] shouldUpdateView = true setNeedsUpdate() } From d703595e5a8c7a43d6dd9ef0471487269fa1c93b Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 16:41:41 -0500 Subject: [PATCH 08/22] TitleLockup TextColor Monarch update Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 6 +- .../TitleLockup/TitleLockupTextColor.swift | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 VDS/Components/TitleLockup/TitleLockupTextColor.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index cd08241d..a9804b9b 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -140,6 +140,7 @@ EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; }; EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.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 */; }; EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */; }; EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; }; @@ -335,6 +336,7 @@ EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = ""; }; EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = ""; }; + EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTextColor.swift; sourceTree = ""; }; EAC71A1C2A2E155A00E47A9F /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; EAC71A1E2A2E173D00E47A9F /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = ""; }; @@ -769,12 +771,13 @@ isa = PBXGroup; children = ( EA5E30522950DDA60082B959 /* TitleLockup.swift */, + EAEEECAC2B1FC1A600531FC2 /* TitleLockupChangeLog.txt */, EA985BEF2968A93600F2FF2E /* TitleLockupEyebrowModel.swift */, EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */, EA985BEB2968A91200F2FF2E /* TitleLockupTitleModel.swift */, + EAC58BFC2BE935C300BA39FA /* TitleLockupTextColor.swift */, EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */, EA513A942A4E1F82002A4DFF /* TitleLockupStyleConfiguration.swift */, - EAEEECAC2B1FC1A600531FC2 /* TitleLockupChangeLog.txt */, ); path = TitleLockup; sourceTree = ""; @@ -1145,6 +1148,7 @@ EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */, EAC925842911C63100091998 /* Colorable.swift in Sources */, 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */, + EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */, EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, diff --git a/VDS/Components/TitleLockup/TitleLockupTextColor.swift b/VDS/Components/TitleLockup/TitleLockupTextColor.swift new file mode 100644 index 00000000..2febd80b --- /dev/null +++ b/VDS/Components/TitleLockup/TitleLockupTextColor.swift @@ -0,0 +1,58 @@ +// +// TitleLockupTextColor.swift +// VDS +// +// Created by Matt Bruce on 5/6/24. +// + +import Foundation +import VDSTokens + +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(String, String) + + 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(.init(hexString: lightColor), .init(hexString: darkColor)).eraseToAnyColorable() + } + } + } + + public enum TitleTextColor: Equatable { + case primary + case custom(String, String) + + 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(.init(hexString: lightColor), .init(hexString: darkColor)).eraseToAnyColorable() + } + } + } +} From 4685c6d3982bee8298805458841b754bdfff6be2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 16:42:12 -0500 Subject: [PATCH 09/22] Implemented TextColor changes to TitleLockup Signed-off-by: Matt Bruce --- VDS/Components/TitleLockup/TitleLockup.swift | 21 ++++--------------- .../TitleLockup/TitleLockupEyebrowModel.swift | 6 ++++++ .../TitleLockupSubTitleModel.swift | 4 ++-- .../TitleLockup/TitleLockupTitleModel.swift | 7 ++++++- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index c0c3b0b5..a838c3b9 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -258,22 +258,10 @@ open class TitleLockup: View { bottomSpacing: VDSLayout.space6X) ]), ]) - - private var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable() - - private var textColorPrimaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark).eraseToAnyColorable() - + //-------------------------------------------------- // 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() { super.updateAccessibility() var elements = [Any]() @@ -330,6 +318,7 @@ open class TitleLockup: View { if let eyebrowModel, !eyebrowModel.text.isEmpty { eyebrowLabel.textAlignment = allLabelsTextAlignment eyebrowLabel.text = eyebrowModel.text + eyebrowLabel.textColorConfiguration = eyebrowModel.textColor.configuration eyebrowLabel.attributes = eyebrowModel.textAttributes eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines eyebrowLabel.surface = surface @@ -339,15 +328,12 @@ open class TitleLockup: View { //When uniform size is true and the title is bold, //the eyebrow is always regular weight and the secondary color. eyebrowLabel.textStyle = otherStandardStyle.value.regular - eyebrowLabel.textColorConfiguration = textColorSecondaryConfiguration } else { //When uniform size is true and the title is regular weight //the eyebrow is always bold and uses the primary color. eyebrowLabel.textStyle = otherStandardStyle.value.bold - eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration } } else { - eyebrowLabel.textColorConfiguration = textColorPrimaryConfiguration eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular } addSubview(eyebrowLabel) @@ -363,6 +349,7 @@ open class TitleLockup: View { if let titleModel, !titleModel.text.isEmpty { titleLabel.textAlignment = allLabelsTextAlignment titleLabel.textStyle = titleModel.textStyle + titleLabel.textColorConfiguration = titleModel.textColor.configuration titleLabel.text = titleModel.text titleLabel.attributes = titleModel.textAttributes titleLabel.numberOfLines = titleModel.numberOfLines @@ -381,7 +368,7 @@ open class TitleLockup: View { if let subTitleModel, !subTitleModel.text.isEmpty { subTitleLabel.textAlignment = allLabelsTextAlignment subTitleLabel.textStyle = otherStandardStyle.value.regular - subTitleLabel.textColorConfiguration = subTitleModel.textColor == .secondary ? textColorSecondaryConfiguration : textColorPrimaryConfiguration + subTitleLabel.textColorConfiguration = subTitleModel.textColor.configuration subTitleLabel.text = subTitleModel.text subTitleLabel.attributes = subTitleModel.textAttributes subTitleLabel.numberOfLines = subTitleModel.numberOfLines diff --git a/VDS/Components/TitleLockup/TitleLockupEyebrowModel.swift b/VDS/Components/TitleLockup/TitleLockupEyebrowModel.swift index 28305bfd..1139a6ee 100644 --- a/VDS/Components/TitleLockup/TitleLockupEyebrowModel.swift +++ b/VDS/Components/TitleLockup/TitleLockupEyebrowModel.swift @@ -13,6 +13,9 @@ extension TitleLockup { /// Text that will be used for the eyebrow label. 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. public var isBold: Bool @@ -26,11 +29,13 @@ extension TitleLockup { public var numberOfLines: Int public init(text: String, + textColor: TextColor = .primary, isBold: Bool = true, standardStyle: OtherStandardStyle = .bodyLarge, textAttributes: [any LabelAttributeModel]? = nil, numberOfLines: Int = 0) { self.text = text + self.textColor = textColor self.isBold = isBold self.standardStyle = standardStyle self.textAttributes = textAttributes @@ -41,3 +46,4 @@ extension TitleLockup { public var textStyle: TextStyle { isBold ? standardStyle.value.bold : standardStyle.value.regular } } } + diff --git a/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift b/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift index f558ffb4..7dcbfb85 100644 --- a/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift +++ b/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift @@ -18,7 +18,7 @@ extension TitleLockup { public var otherStandardStyle: OtherStandardStyle /// 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. public var textAttributes: [any LabelAttributeModel]? @@ -31,7 +31,7 @@ extension TitleLockup { public init(text: String, otherStandardStyle: OtherStandardStyle = .bodyLarge, - textColor: Use = .primary, + textColor: TextColor = .primary, textAttributes: [any LabelAttributeModel]? = nil, numberOfLines: Int = 0, lineBreakMode: NSLineBreakMode = .byWordWrapping) { diff --git a/VDS/Components/TitleLockup/TitleLockupTitleModel.swift b/VDS/Components/TitleLockup/TitleLockupTitleModel.swift index 7541151f..2d7f7405 100644 --- a/VDS/Components/TitleLockup/TitleLockupTitleModel.swift +++ b/VDS/Components/TitleLockup/TitleLockupTitleModel.swift @@ -14,7 +14,10 @@ extension TitleLockup { /// Text that will be used for the title label. 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]? /// 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 init(text: String, + textColor: TitleTextColor = .primary, textAttributes: [any LabelAttributeModel]? = nil, isBold: Bool = true, standardStyle: TitleStandardStyle = .featureXSmall, numberOfLines: Int = 0, lineBreakMode: NSLineBreakMode = .byTruncatingTail) { self.text = text + self.textColor = textColor self.isBold = isBold self.textAttributes = textAttributes self.standardStyle = standardStyle From 46a14712823429735590f56581eb632020cab3fb Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 16:49:21 -0500 Subject: [PATCH 10/22] implement Monarch in Tilelet (first cut) Signed-off-by: Matt Bruce --- .../TileContainer/TileContainer.swift | 25 +++++++++++-------- VDS/Components/Tilelet/Tilelet.swift | 12 ++++++--- .../Tilelet/TileletSubTitleModel.swift | 9 ++++--- .../Tilelet/TileletTitleModel.swift | 10 +++++++- .../Tilelet/TiletEyebrowModel.swift | 11 +++++++- VDS/Extensions/UIColor+VDSColor.swift | 6 +++++ 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 314b16b8..eb356ecc 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -132,7 +132,7 @@ open class TileContainerBase: Control where Padding open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } } /// 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. open var backgroundEffect: BackgroundEffect = .none { didSet { setNeedsUpdate() } } @@ -192,13 +192,13 @@ open class TileContainerBase: Control where Padding // MARK: - Configuration //-------------------------------------------------- private let cornerRadius = VDSFormControls.borderRadius * 2 - private var backgroundColorConfiguration = BackgroundColorConfiguration() + internal var backgroundColorConfiguration = BackgroundColorConfiguration() private let dropShadowConfiguration = DropShadowConfiguration().with { $0.shadowColorConfiguration = SurfaceColorConfiguration().with { $0.lightColor = VDSColor.elementsPrimaryOnlight }.eraseToAnyColorable() $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) } @@ -325,7 +325,7 @@ open class TileContainerBase: Control where Padding } applyBackgroundEffects() - + if showDropShadow, surface == .light { addDropShadow(dropShadowConfiguration) } else { @@ -457,17 +457,22 @@ extension TileContainerBase { required init() { } 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: - primaryColorConfig.getColor(object.surface) + return primaryColorConfig.getColor(object.surface) case .secondary: - secondaryColorConfig.getColor(object.surface) + return secondaryColorConfig.getColor(object.surface) case .white: - whiteColorConfig.getColor(object.surface) + return whiteColorConfig.getColor(object.surface) case .black: - blackColorConfig.getColor(object.surface) + return blackColorConfig.getColor(object.surface) case .custom(let hexCode): - UIColor(hexString: hexCode) + return UIColor(hexString: hexCode) } } } diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index fe9fe7f1..f0814e11 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -102,6 +102,10 @@ open class Tilelet: TileContainerBase { $0.backgroundColor = .clear } + private var backgroundColorSurface: Surface { + backgroundColorConfiguration.getColor(self).surface + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -444,7 +448,7 @@ open class Tilelet: TileContainerBase { badge.text = badgeModel.text badge.fillColor = badgeModel.fillColor badge.numberOfLines = badgeModel.numberOfLines - badge.surface = badgeModel.surface + badge.surface = backgroundColorSurface badge.maxWidth = badgeModel.maxWidth badgeLabelHeightGreaterThanConstraint?.constant = badge.label.minimumLineHeight if badgeContainerView.superview == nil { @@ -474,7 +478,7 @@ open class Tilelet: TileContainerBase { if showTitleLockup { //flip the surface for the titleLockup - titleLockup.surface = color == .black ? Surface.dark : Surface.light + titleLockup.surface = backgroundColorSurface //titleLockup if let textWidth { @@ -529,14 +533,14 @@ open class Tilelet: TileContainerBase { if let descriptiveIconModel { descriptiveIcon.name = descriptiveIconModel.name descriptiveIcon.size = descriptiveIconModel.size - descriptiveIcon.surface = descriptiveIconModel.surface + descriptiveIcon.surface = backgroundColorSurface descriptiveIcon.accessibilityLabel = descriptiveIconModel.accessibleText showIconContainerView = true } if let directionalIconModel { directionalIcon.size = directionalIconModel.size - directionalIcon.surface = directionalIconModel.surface + directionalIcon.surface = backgroundColorSurface directionalIcon.accessibilityLabel = "Right arrow" showIconContainerView = true } diff --git a/VDS/Components/Tilelet/TileletSubTitleModel.swift b/VDS/Components/Tilelet/TileletSubTitleModel.swift index fb68ff53..4c48cc3a 100644 --- a/VDS/Components/Tilelet/TileletSubTitleModel.swift +++ b/VDS/Components/Tilelet/TileletSubTitleModel.swift @@ -36,8 +36,8 @@ extension Tilelet { public var textAttributes: [any LabelAttributeModel]? /// 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. public var lineBreakMode: NSLineBreakMode @@ -46,7 +46,7 @@ extension Tilelet { //-------------------------------------------------- public init(text: String, otherStandardStyle: OtherStandardStyle = .bodySmall, - textColor: Use = .primary, + textColor: TitleLockup.TextColor = .primary, textAttributes: [any LabelAttributeModel]? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) { self.text = text @@ -64,7 +64,8 @@ extension Tilelet { TitleLockup.SubTitleModel(text: text, otherStandardStyle: otherStandardStyle.value, textColor: textColor, - textAttributes: textAttributes, lineBreakMode: lineBreakMode) + textAttributes: textAttributes, + lineBreakMode: lineBreakMode) } } } diff --git a/VDS/Components/Tilelet/TileletTitleModel.swift b/VDS/Components/Tilelet/TileletTitleModel.swift index fa8c603d..b9bc7bbe 100644 --- a/VDS/Components/Tilelet/TileletTitleModel.swift +++ b/VDS/Components/Tilelet/TileletTitleModel.swift @@ -32,6 +32,9 @@ extension Tilelet { /// Text that will be used for the title label. 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. public var isBold: Bool = false /// Text attributes that will be used for the title label. @@ -47,11 +50,13 @@ extension Tilelet { // MARK: - Initializers //-------------------------------------------------- public init(text: String, + textColor: TitleLockup.TitleTextColor = .primary, textAttributes: [any LabelAttributeModel]? = nil, isBold: Bool = true, standardStyle: StandardStyle = .titleSmall, lineBreakMode: NSLineBreakMode = .byTruncatingTail) { self.text = text + self.textColor = textColor self.textAttributes = textAttributes self.standardStyle = standardStyle self.isBold = isBold @@ -64,8 +69,11 @@ extension Tilelet { /// Converts this type of model to a TitleLockup.TitleModel. public func toTitleLockupTitleModel() -> TitleLockup.TitleModel { TitleLockup.TitleModel(text: text, + textColor: textColor, textAttributes: textAttributes, - isBold: isBold, standardStyle: standardStyle.value, lineBreakMode: lineBreakMode) + isBold: isBold, + standardStyle: standardStyle.value, + lineBreakMode: lineBreakMode) } } } diff --git a/VDS/Components/Tilelet/TiletEyebrowModel.swift b/VDS/Components/Tilelet/TiletEyebrowModel.swift index e7c008b4..3d22ab74 100644 --- a/VDS/Components/Tilelet/TiletEyebrowModel.swift +++ b/VDS/Components/Tilelet/TiletEyebrowModel.swift @@ -18,6 +18,9 @@ extension Tilelet { /// Text that will be used for the eyebrow label. 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. public var isBold: Bool = false /// Text attributes that will be used for the eyebrow label. @@ -33,11 +36,13 @@ extension Tilelet { // MARK: - Initializers //-------------------------------------------------- public init(text: String, + textColor: TitleLockup.TextColor = .primary, textAttributes: [any LabelAttributeModel]? = nil, isBold: Bool = true, standardStyle: Tilelet.SubTitleModel.OtherStandardStyle = .bodySmall, lineBreakMode: NSLineBreakMode = .byTruncatingTail) { self.text = text + self.textColor = textColor self.textAttributes = textAttributes self.standardStyle = standardStyle self.isBold = isBold @@ -49,7 +54,11 @@ extension Tilelet { //-------------------------------------------------- /// Converts this type of model to a TitleLockup.TitleModel. 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) } } } diff --git a/VDS/Extensions/UIColor+VDSColor.swift b/VDS/Extensions/UIColor+VDSColor.swift index c622db33..9b165f64 100644 --- a/VDS/Extensions/UIColor+VDSColor.swift +++ b/VDS/Extensions/UIColor+VDSColor.swift @@ -176,4 +176,10 @@ extension UIColor { guard let found else { return nil} return found } + + public var surface: Surface { + var greyScale: CGFloat = 0 + getWhite(&greyScale, alpha: nil) + return greyScale < 0.5 ? .dark : .light + } } From 6a07bcdd4c46609372c970551cb2c6c8afb7dbdd Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 17:06:38 -0500 Subject: [PATCH 11/22] added accessiblityText property to badgeindicator Signed-off-by: Matt Bruce --- VDS/Components/BadgeIndicator/BadgeIndicator.swift | 5 ++++- VDS/Components/Icon/ButtonIcon/ButtonIcon.swift | 1 + .../Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index a327270d..aae927a8 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -210,6 +210,7 @@ open class BadgeIndicator: View { /// The Container's height. open var height: CGFloat? { didSet { setNeedsUpdate() } } + open var accessibilityText: String? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -348,7 +349,9 @@ open class BadgeIndicator: View { open override func updateAccessibility() { super.updateAccessibility() - if kind == .numbered { + if let accessibilityText { + accessibilityLabel = accessibilityText + } else if kind == .numbered { accessibilityLabel = label.text } else { accessibilityLabel = "Simple" diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index b97a1fac..5ba6a9fe 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -544,6 +544,7 @@ open class ButtonIcon: Control, Changeable { badgeIndicator.horizontalPadding = badgeIndicatorModel.horizontalPadding badgeIndicator.hideDot = badgeIndicatorModel.hideDot badgeIndicator.hideBorder = badgeIndicatorModel.hideBorder + badgeIndicator.accessibilityText = badgeIndicatorModel.accessibilityText } private func updateExpandDirectionalConstraints() { diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift b/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift index e1c04b23..28d731b0 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift @@ -46,6 +46,9 @@ extension ButtonIcon { /// Trailing Text height that will be used for the badge indicator. public var trailingText: String? + /// Accessibliity Text + public var accessibilityText: String? + /// Dot Size that will be used for the badge indicator. public var dotSize: CGFloat? @@ -61,7 +64,7 @@ extension ButtonIcon { /// Hide Border that will be used for the badge indicator. public var hideBorder: Bool = false - public init(kind: BadgeIndicator.Kind = .simple, fillColor: BadgeIndicator.FillColor = .red, expandDirection: ExpandDirection = .right, size: BadgeIndicator.Size = .xxlarge, maximumDigits: BadgeIndicator.MaximumDigits = .two, width: CGFloat? = nil, height: CGFloat? = nil, number: Int? = nil, leadingCharacter: String? = "", trailingText: String? = "", dotSize: CGFloat? = nil, verticalPadding: CGFloat? = nil, horizontalPadding: CGFloat? = nil, hideDot: Bool = false, hideBorder: Bool = false) { + 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.fillColor = fillColor self.expandDirection = expandDirection @@ -70,6 +73,7 @@ extension ButtonIcon { self.width = width self.height = height self.number = number + self.accessibilityText = accessibilityText self.leadingCharacter = leadingCharacter self.trailingText = trailingText self.dotSize = dotSize From aa3b11efc15242a8a11f340cce3e35ed2d74eb28 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 18:40:48 -0500 Subject: [PATCH 12/22] refactored hexstring to uicolor Signed-off-by: Matt Bruce --- VDS/Components/TileContainer/TileContainer.swift | 6 +++--- VDS/Components/TitleLockup/TitleLockupTextColor.swift | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index eb356ecc..61d7a941 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -81,7 +81,7 @@ open class TileContainerBase: Control where Padding /// Enum used to describe the background effect choices used for this component. public enum BackgroundEffect { case transparency - case gradient(String, String) + case gradient(UIColor, UIColor) case none } @@ -199,7 +199,7 @@ open class TileContainerBase: Control where Padding }.eraseToAnyColorable() $0.shadowOffsetConfiguration = .init(.init(width: 0, height: 6), .zero) $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 { @@ -391,7 +391,7 @@ open class TileContainerBase: Control where Padding removeGradientLayer() case .gradient(let firstColor, let secondColor): alphaConfiguration = 1.0 - addGradientLayer(with: UIColor(hexString: firstColor), secondColor: UIColor(hexString: secondColor)) + addGradientLayer(with: firstColor, secondColor: secondColor) backgroundImageView.isHidden = true backgroundImageView.alpha = 1.0 case .none: diff --git a/VDS/Components/TitleLockup/TitleLockupTextColor.swift b/VDS/Components/TitleLockup/TitleLockupTextColor.swift index 2febd80b..c0760b6f 100644 --- a/VDS/Components/TitleLockup/TitleLockupTextColor.swift +++ b/VDS/Components/TitleLockup/TitleLockupTextColor.swift @@ -7,6 +7,7 @@ import Foundation import VDSTokens +import UIKit extension TitleLockup { private static var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable() @@ -16,7 +17,7 @@ extension TitleLockup { public enum TextColor: Equatable { case primary case secondary - case custom(String, String) + case custom(UIColor, UIColor) private var reflectedValue: String { String(reflecting: self) } @@ -31,15 +32,15 @@ extension TitleLockup { case .secondary: TitleLockup.textColorSecondaryConfiguration case .custom(let lightColor, let darkColor): - SurfaceColorConfiguration(.init(hexString: lightColor), .init(hexString: darkColor)).eraseToAnyColorable() + SurfaceColorConfiguration(lightColor, darkColor).eraseToAnyColorable() } } } public enum TitleTextColor: Equatable { case primary - case custom(String, String) - + case custom(UIColor, UIColor) + private var reflectedValue: String { String(reflecting: self) } public static func == (lhs: Self, rhs: Self) -> Bool { @@ -51,7 +52,7 @@ extension TitleLockup { case .primary: TitleLockup.textColorPrimaryConfiguration case .custom(let lightColor, let darkColor): - SurfaceColorConfiguration(.init(hexString: lightColor), .init(hexString: darkColor)).eraseToAnyColorable() + SurfaceColorConfiguration(lightColor, darkColor).eraseToAnyColorable() } } } From b92bb553b19fa12062ed7fe9242b8d701bb4fcbf Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 18:41:23 -0500 Subject: [PATCH 13/22] intial date work for input Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index eb67c255..00e7404f 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -165,11 +165,12 @@ open class InputField: EntryFieldBase { controlStackView.addArrangedSubview(textField) textField.heightAnchor.constraint(equalToConstant: 20).isActive = true + textField.delegate = self textField .textPublisher .sink { [weak self] newText in print("textPublisher newText: \(newText)") - self?.text = newText + self?.process(text: newText) self?.validate() self?.sendActions(for: .valueChanged) }.store(in: &subscribers) @@ -280,6 +281,7 @@ open class InputField: EntryFieldBase { var toolTipModel: Tooltip.TooltipModel? = tooltipModel var isSecureTextEntry = false var rules = [AnyRule]() + var placeholderText: String? if self.isRequired { let rule = RequiredRule() @@ -326,6 +328,7 @@ open class InputField: EntryFieldBase { case .date: minWidth = 114.0 + placeholderText = dateFormat.placeholderText case .securityCode: minWidth = 88.0 @@ -364,6 +367,9 @@ open class InputField: EntryFieldBase { minWidthConstraint?.isActive = true } + //placeholder + textField.placeholder = placeholderText + //tooltip tooltipModel = toolTipModel } @@ -421,6 +427,47 @@ open class InputField: EntryFieldBase { open var hidePasswordButtonText: String = "Hide" { 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 { @@ -442,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 + } + } + + } +} From fbd188cae85e89b2992cadd7391a26be2fc74ea0 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 19:11:50 -0500 Subject: [PATCH 14/22] refactored color Signed-off-by: Matt Bruce --- VDS/Components/TileContainer/TileContainer.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 61d7a941..000eb676 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -69,7 +69,7 @@ open class TileContainerBase: Control where Padding case secondary case white case black - case custom(String) + case custom(UIColor) private var reflectedValue: String { String(reflecting: self) } @@ -471,8 +471,8 @@ extension TileContainerBase { return whiteColorConfig.getColor(object.surface) case .black: return blackColorConfig.getColor(object.surface) - case .custom(let hexCode): - return UIColor(hexString: hexCode) + case .custom(let color): + return color } } } From 9982eddce9bfde2de3f9d7a10ba5783bd6c48c65 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 13:55:25 -0500 Subject: [PATCH 15/22] CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index bd4df763..b1010176 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -104,6 +104,7 @@ open class Notification: View { open var typeIcon = Icon().with { $0.name = .infoBold $0.size = UIDevice.isIPad ? .medium : .small + $0.accessibilityTraits.remove(.image) } /// Icon used for the close. From 6236184481553481bc547a0b3b99e91f9610e496 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 13:56:03 -0500 Subject: [PATCH 16/22] release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 7cea34d5..cad514ec 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,7 @@ +1.0.62 +---------------- +- CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. + 1.0.61 ---------------- - CXTDT-552068 - Text Area - Text padding From fb23a411b9c43df3dd9e4f080b36768e52d0ab16 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:26:39 -0500 Subject: [PATCH 17/22] CXTDT-553663 - DropdownSelect - Accessibility - 5 issues Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index e86b3792..80f94988 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -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. open override func setup() { super.setup() - - accessibilityLabel = "Dropdown Select" // stackview for controls in EntryFieldBase.controlContainerView let controlStackView = UIStackView().with { @@ -118,6 +116,10 @@ open class DropdownSelect: EntryFieldBase { controlStackView.addArrangedSubview(inlineDisplayLabel) controlStackView.addArrangedSubview(selectedOptionLabel) + containerStackView.isAccessibilityElement = true + containerStackView.accessibilityLabel = "Dropdown Select" + inlineDisplayLabel.isAccessibilityElement = true + controlStackView.setCustomSpacing(0, after: dropdownField) controlStackView.setCustomSpacing(VDSLayout.space1X, after: inlineDisplayLabel) controlStackView.setCustomSpacing(VDSLayout.space3X, after: selectedOptionLabel) @@ -245,9 +247,41 @@ open class DropdownSelect: EntryFieldBase { 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() { optionsPicker.isHidden = true dropdownField.resignFirstResponder() + setNeedsUpdate() + UIAccessibility.post(notification: .layoutChanged, argument: containerStackView) } } @@ -258,6 +292,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { internal func launchPicker() { if optionsPicker.isHidden { + UIAccessibility.post(notification: .layoutChanged, argument: optionsPicker) dropdownField.becomeFirstResponder() } else { dropdownField.resignFirstResponder() From 5d1cdcfdff62d772feb8b29c901ffe6eedd2df4c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:27:00 -0500 Subject: [PATCH 18/22] refactored accessibility elements Signed-off-by: Matt Bruce --- .../Attributes/TooltipLabelAttribute.swift | 2 +- .../TextFields/EntryFieldBase.swift | 2 +- .../TextFields/InputField/InputField.swift | 27 +++++++++++++---- .../TextFields/TextArea/TextArea.swift | 29 +++++++++++++++---- VDS/Components/Tooltip/TooltipModel.swift | 3 ++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 20666b10..6b03d103 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -77,7 +77,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable self.subscriber = subscriber self.surface = surface self.model = model - self.accessibleText = accessibleText + self.accessibleText = accessibleText ?? model.accessibleText self.presenter = presenter //create the tooltip click event diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 644a8de1..5c549564 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -207,7 +207,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open override func setup() { super.setup() - isAccessibilityElement = true + isAccessibilityElement = false addSubview(stackView) //create the wrapping view diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 640538fe..eb67c255 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -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. open override func setup() { super.setup() - isAccessibilityElement = false minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) minWidthConstraint?.isActive = true @@ -373,11 +372,29 @@ open class InputField: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() textField.accessibilityLabel = showError ? "error" : nil - if showError { - accessibilityElements = [titleLabel, textField, statusIcon, errorLabel, helperLabel] - } else { - accessibilityElements = [titleLabel, textField, helperLabel] + } + + open override var accessibilityElements: [Any]? { + 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 } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 7229c4a9..5ea944a3 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -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. open override func setup() { super.setup() - isAccessibilityElement = false containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true @@ -264,13 +263,31 @@ open class TextArea: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() 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 func resignFirstResponder() -> Bool { diff --git a/VDS/Components/Tooltip/TooltipModel.swift b/VDS/Components/Tooltip/TooltipModel.swift index ee690d74..461fda66 100644 --- a/VDS/Components/Tooltip/TooltipModel.swift +++ b/VDS/Components/Tooltip/TooltipModel.swift @@ -17,16 +17,19 @@ extension Tooltip { public var title: String? public var content: String? public var contentView: UIView? + public var accessibleText: String? public var contentViewAlignment: UIStackView.Alignment? public init(closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil, + accessibleText: String? = "Tooltip", contentViewAlignment: UIStackView.Alignment = .leading) { self.closeButtonText = closeButtonText self.title = title self.content = content self.contentView = contentView + self.accessibleText = accessibleText self.contentViewAlignment = contentViewAlignment } } From 070aa285ae5143dbf63d76db6d2af815c2239cb2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:27:35 -0500 Subject: [PATCH 19/22] updated release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index cad514ec..258951db 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,6 +1,7 @@ 1.0.62 ---------------- - CXTDT-546824 - Notification - Accessibility - Redundant text is provided for the notification icon. +- CXTDT-553663 - DropdownSelect - Accessibility - 5 issues 1.0.61 ---------------- From fd0c8a27ece52bfdfc2a6fe8bfe3cfa483e39561 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 3 May 2024 15:34:03 -0500 Subject: [PATCH 20/22] updated tooltip accessible main view Signed-off-by: Matt Bruce --- VDS/Components/Tooltip/TooltipDialog.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Tooltip/TooltipDialog.swift b/VDS/Components/Tooltip/TooltipDialog.swift index 9822baae..a9ee3714 100644 --- a/VDS/Components/Tooltip/TooltipDialog.swift +++ b/VDS/Components/Tooltip/TooltipDialog.swift @@ -48,7 +48,6 @@ open class TooltipDialog: View, UIScrollViewDelegate { lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with { $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() primaryAccessibilityElement.accessibilityHint = "Double tap on the \(tooltipModel.closeButtonText) button to close." - + primaryAccessibilityElement.accessibilityFrameInContainerSpace = .init(origin: .zero, size: frame.size) + var elements: [Any] = [primaryAccessibilityElement] contentStackView.arrangedSubviews.forEach{ elements.append($0) } elements.append(closeButton) From 91cb21eb0482d4c2bcae231c2c8d8215db6fc96e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 09:24:30 -0500 Subject: [PATCH 21/22] added done button Signed-off-by: Matt Bruce --- .../TextFields/InputField/TextField.swift | 38 +++++++++++++++++++ .../TextFields/TextArea/TextView.swift | 19 +++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 14178020..9a96829e 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -10,6 +10,25 @@ import UIKit @objc(VDSTextField) 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 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 { let success = super.becomeFirstResponder() if isSecureTextEntry, let text { diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index c35b4a80..efe8164b 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -97,7 +97,6 @@ open class TextView: UITextView, ViewProtocol { initialSetupPerformed = true backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false - accessibilityCustomActions = [] setup() setNeedsUpdate() } @@ -106,8 +105,25 @@ open class TextView: UITextView, ViewProtocol { open func setup() { 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() { updateLabel() } @@ -118,7 +134,6 @@ open class TextView: UITextView, ViewProtocol { shouldUpdateView = false surface = .light text = nil - accessibilityCustomActions = [] shouldUpdateView = true setNeedsUpdate() } From 5ec6046bed00abe2a2d13ca74abf05614298bbb8 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 6 May 2024 17:06:38 -0500 Subject: [PATCH 22/22] added accessiblityText property to badgeindicator Signed-off-by: Matt Bruce --- VDS/Components/BadgeIndicator/BadgeIndicator.swift | 5 ++++- VDS/Components/Icon/ButtonIcon/ButtonIcon.swift | 1 + .../Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index a327270d..aae927a8 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -210,6 +210,7 @@ open class BadgeIndicator: View { /// The Container's height. open var height: CGFloat? { didSet { setNeedsUpdate() } } + open var accessibilityText: String? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -348,7 +349,9 @@ open class BadgeIndicator: View { open override func updateAccessibility() { super.updateAccessibility() - if kind == .numbered { + if let accessibilityText { + accessibilityLabel = accessibilityText + } else if kind == .numbered { accessibilityLabel = label.text } else { accessibilityLabel = "Simple" diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index b97a1fac..5ba6a9fe 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -544,6 +544,7 @@ open class ButtonIcon: Control, Changeable { badgeIndicator.horizontalPadding = badgeIndicatorModel.horizontalPadding badgeIndicator.hideDot = badgeIndicatorModel.hideDot badgeIndicator.hideBorder = badgeIndicatorModel.hideBorder + badgeIndicator.accessibilityText = badgeIndicatorModel.accessibilityText } private func updateExpandDirectionalConstraints() { diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift b/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift index e1c04b23..28d731b0 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIconBadgeIndicatorModel.swift @@ -46,6 +46,9 @@ extension ButtonIcon { /// Trailing Text height that will be used for the badge indicator. public var trailingText: String? + /// Accessibliity Text + public var accessibilityText: String? + /// Dot Size that will be used for the badge indicator. public var dotSize: CGFloat? @@ -61,7 +64,7 @@ extension ButtonIcon { /// Hide Border that will be used for the badge indicator. public var hideBorder: Bool = false - public init(kind: BadgeIndicator.Kind = .simple, fillColor: BadgeIndicator.FillColor = .red, expandDirection: ExpandDirection = .right, size: BadgeIndicator.Size = .xxlarge, maximumDigits: BadgeIndicator.MaximumDigits = .two, width: CGFloat? = nil, height: CGFloat? = nil, number: Int? = nil, leadingCharacter: String? = "", trailingText: String? = "", dotSize: CGFloat? = nil, verticalPadding: CGFloat? = nil, horizontalPadding: CGFloat? = nil, hideDot: Bool = false, hideBorder: Bool = false) { + 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.fillColor = fillColor self.expandDirection = expandDirection @@ -70,6 +73,7 @@ extension ButtonIcon { self.width = width self.height = height self.number = number + self.accessibilityText = accessibilityText self.leadingCharacter = leadingCharacter self.trailingText = trailingText self.dotSize = dotSize