diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index a5403c49..ee0265b4 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -1535,7 +1535,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1573,7 +1573,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index 17ededf4..83450403 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -214,7 +214,7 @@ extension DatePicker { calendar.indicators = calendarModel.indicators calendar.maxDate = calendarModel.maxDate calendar.minDate = calendarModel.minDate - calendar.surface = calendarModel.surface + calendar.surface = surface calendar.setNeedsLayout() calendar.layoutIfNeeded() @@ -223,7 +223,7 @@ extension DatePicker { //find scrollView if scrollView == nil { - scrollView = findScrollView(from: containerView) + scrollView = containerView.findSuperview(ofType: UIScrollView.self) scrollViewContentSize = scrollView?.contentSize } @@ -348,17 +348,6 @@ extension DatePicker { } } - private func findScrollView(from view: UIView) -> UIScrollView? { - var currentView = view - while let superview = currentView.superview { - if let scrollView = superview as? UIScrollView { - return scrollView - } - currentView = superview - } - return nil - } - private func calculatePopoverPosition(relativeTo sourceView: UIView, in parentView: UIView, size: CGSize, with spacing: CGFloat) -> CGPoint? { let sourceFrameInParent = sourceView.convert(sourceView.bounds, to: parentView) let parentBounds = parentView.bounds @@ -442,3 +431,16 @@ extension DatePicker { } } } + +extension UIView { + public func findSuperview(ofType type: T.Type) -> T? { + var currentView: UIView? = self + while let view = currentView { + if let superview = view.superview as? T { + return superview + } + currentView = view.superview + } + return nil + } +} diff --git a/VDS/Components/DatePicker/DatePickerCalendarModel.swift b/VDS/Components/DatePicker/DatePickerCalendarModel.swift index ccceb5c9..16a46e61 100644 --- a/VDS/Components/DatePicker/DatePickerCalendarModel.swift +++ b/VDS/Components/DatePicker/DatePickerCalendarModel.swift @@ -10,8 +10,6 @@ import UIKit extension DatePicker { public struct CalendarModel { - public let surface: Surface - /// If set to true, the calendar will not have a border. public let hideContainerBorder: Bool @@ -35,15 +33,13 @@ extension DatePicker { /// Array of ``CalendarIndicatorModel`` you are wanting to show on legend. public let indicators: [CalendarBase.CalendarIndicatorModel] - public init(surface: Surface = .light, - hideContainerBorder: Bool = false, + public init(hideContainerBorder: Bool = false, hideCurrentDateIndicator: Bool = false, activeDates: [Date] = [], inactiveDates: [Date] = [], minDate: Date = Date().startOfMonth, maxDate: Date = Date().endOfMonth, indicators: [CalendarBase.CalendarIndicatorModel] = []) { - self.surface = surface self.hideContainerBorder = hideContainerBorder self.hideCurrentDateIndicator = hideCurrentDateIndicator self.activeDates = activeDates diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 562e1e54..872a4d05 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -214,7 +214,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { selectorView.isAccessibilityElement = true selectorView.accessibilityTraits = .button addSubview(selectorView) - selectorView.isUserInteractionEnabled = true + selectorView.isUserInteractionEnabled = false selectorView.addSubview(selectorStackView) diff --git a/VDS/Components/TextFields/InputField/FieldTypes/FieldType.swift b/VDS/Components/TextFields/InputField/FieldTypes/FieldType.swift index b3c2a92b..180478af 100644 --- a/VDS/Components/TextFields/InputField/FieldTypes/FieldType.swift +++ b/VDS/Components/TextFields/InputField/FieldTypes/FieldType.swift @@ -68,6 +68,12 @@ extension InputField { actionModel.onClick(inputField) } inputField.actionTextLink.isHidden = false + // set the accessibilityLabel + if let labelText = inputField.labelText { + inputField.actionTextLink.bridge_accessibilityLabelBlock = { + return "\(actionModel.text) \(labelText)" + } + } inputField.fieldStackView.setCustomSpacing(VDSLayout.space2X, after: inputField.statusIcon) } else { inputField.actionTextLink.isHidden = true diff --git a/VDS/Components/TextFields/InputField/FieldTypes/Password.swift b/VDS/Components/TextFields/InputField/FieldTypes/Password.swift index 00c00a0d..7d45d091 100644 --- a/VDS/Components/TextFields/InputField/FieldTypes/Password.swift +++ b/VDS/Components/TextFields/InputField/FieldTypes/Password.swift @@ -41,7 +41,7 @@ extension InputField { guard let self else { return } self.passwordActionType = nextPasswordActionType inputField.setNeedsUpdate() - }) + }) } else { passwordActionType = .show } diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f7f54896..11a8ae17 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -105,6 +105,8 @@ open class InputField: EntryFieldBase { $0.translatesAutoresizingMaskIntoConstraints = false $0.textStyle = TextStyle.bodyLarge $0.isAccessibilityElement = false + $0.autocorrectionType = .no + $0.spellCheckingType = .no } /// Color configuration for the textField. @@ -360,7 +362,11 @@ extension InputField: UITextFieldDelegate { } public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - return fieldType.handler().textField(self, textField: textField, shouldChangeCharactersIn: range, replacementString: string) + let shouldChange = fieldType.handler().textField(self, textField: textField, shouldChangeCharactersIn: range, replacementString: string) + if shouldChange { + UIAccessibility.post(notification: .announcement, argument: string) + } + return shouldChange } } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index d0396d7a..c668a851 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -101,6 +101,7 @@ open class TextArea: EntryFieldBase { $0.isScrollEnabled = true $0.textContainerInset = .zero $0.autocorrectionType = .no + $0.spellCheckingType = .no $0.textContainer.lineFragmentPadding = 0 } @@ -132,6 +133,7 @@ open class TextArea: EntryFieldBase { super.setup() accessibilityHintText = "Double tap to edit" + textView.delegate = self //events textView @@ -226,7 +228,7 @@ open class TextArea: EntryFieldBase { } } - func textViewDidChange(_ textView: UITextView) { + public func textViewDidChange(_ textView: UITextView) { //dynamic textView Height sizing based on Figma //if you want it to work "as-is" delete this code @@ -288,3 +290,10 @@ open class TextArea: EntryFieldBase { //-------------------------------------------------- var countRule = CharacterCountRule() } + +extension TextArea: UITextViewDelegate { + public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + UIAccessibility.post(notification: .announcement, argument: text) + return true + } +} diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 615c0b40..e52332ff 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -205,15 +205,10 @@ open class Tilelet: TileContainerBase { } /// Descriptive Icon positioned in the contentView. - open var descriptiveIcon = Icon().with { - $0.isAccessibilityElement = false - } + open var descriptiveIcon = Icon() /// Directional Icon positioned in the contentView. - open var directionalIcon = Icon().with { - $0.isAccessibilityElement = false - $0.name = .rightArrow - } + open var directionalIcon = Icon() private var _textWidth: TextWidth? @@ -304,7 +299,7 @@ open class Tilelet: TileContainerBase { super.setup() color = .black aspectRatio = .none - + addContentView(stackView) //badge @@ -382,6 +377,16 @@ open class Tilelet: TileContainerBase { titleLockupSubTitleLabelHeightGreaterThanConstraint = titleLockup.subTitleLabel.heightGreaterThanEqualTo(constant: titleLockup.subTitleLabel.minimumLineHeight) titleLockupSubTitleLabelHeightGreaterThanConstraint?.priority = .defaultHigh titleLockupSubTitleLabelHeightGreaterThanConstraint?.activate() + + directionalIcon.bridge_accessibilityLabelBlock = { [weak self] in + guard let self, let directionalIconModel else { return nil } + return directionalIconModel.accessibleText + } + + descriptiveIcon.bridge_accessibilityLabelBlock = { [weak self] in + guard let self, let descriptiveIconModel else { return nil } + return descriptiveIconModel.accessibleText + } } /// Resets to default settings. @@ -425,6 +430,14 @@ open class Tilelet: TileContainerBase { let titleLockupViews = gatherAccessibilityElements(from: titleLockup) views.append(contentsOf: titleLockupViews) } + + if descriptiveIconModel != nil { + views.append(descriptiveIcon) + + } else if directionalIconModel != nil { + views.append(directionalIcon) + } + containerView.setAccessibilityLabel(for: views) // get the views to return diff --git a/VDS/Components/Tilelet/TileletIconModels.swift b/VDS/Components/Tilelet/TileletIconModels.swift index 58057942..03b2d225 100644 --- a/VDS/Components/Tilelet/TileletIconModels.swift +++ b/VDS/Components/Tilelet/TileletIconModels.swift @@ -66,6 +66,10 @@ extension Tilelet { public var iconName: Icon.Name { return self == .rightArrow ? .rightArrow : .externalLink } + + public var accessibilityLabel: String { + self == .rightArrow ? "Directional right arrow" : "External link" + } } public enum IconSize: String, EnumSubset { @@ -80,7 +84,7 @@ extension Tilelet { public var iconColor: IconColor? /// Accessible Text for the Icon - public var accessibleText: String + public var accessibleText: String? /// Enum for a icon type you want shown.. public var iconType: IconType @@ -95,7 +99,7 @@ extension Tilelet { self.iconType = iconType self.iconColor = iconColor - self.accessibleText = accessibleText ?? iconType.iconName.rawValue + self.accessibleText = accessibleText ?? iconType.accessibilityLabel self.size = size } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 54be0815..6ea73a9b 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,14 @@ +1.0.71 +---------------- +- CXTDT-581803 - DatePicker - Calendar does not switch to Dark Mode + +1.0.70 +---------------- +- CXTDT-577463 - InputField - Accessibility - #1 Typing Feedback +- CXTDT-577463 - InputField - Accessibility - #5 Password / Inline Action +- CXTDT-560485 - Tilelet - Accessibility Icons +- DatePicker - Final logic for how the calendar shows. + 1.0.69 ---------------- - DatePicker - Refactored how this is shown