diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index fd3e3452..b023cf90 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -126,7 +126,7 @@ open class CalendarBase: Control, Changeable { /// 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 = true + isAccessibilityElement = false accessibilityLabel = "Calendar" addSubview(containerView) containerView diff --git a/VDS/Components/Calendar/CalendarFooterReusableView.swift b/VDS/Components/Calendar/CalendarFooterReusableView.swift index 9547084f..bdab58b5 100644 --- a/VDS/Components/Calendar/CalendarFooterReusableView.swift +++ b/VDS/Components/Calendar/CalendarFooterReusableView.swift @@ -31,6 +31,8 @@ class CalendarFooterReusableView: UICollectionReusableView { internal var containerView = View().with { $0.clipsToBounds = true + $0.isAccessibilityElement = true + $0.accessibilityLabel = "Legend" } private let flowLayout = LeftAlignedCollectionViewFlowLayout().with { @@ -39,7 +41,7 @@ class CalendarFooterReusableView: UICollectionReusableView { $0.minimumInteritemSpacing = VDSLayout.space4X $0.scrollDirection = .vertical } - + open lazy var legendCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout).with { $0.isScrollEnabled = false $0.translatesAutoresizingMaskIntoConstraints = false @@ -55,7 +57,8 @@ class CalendarFooterReusableView: UICollectionReusableView { } private var topConstraint: NSLayoutConstraint? - + private var legendLabels: [Label] = [] + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -69,6 +72,13 @@ class CalendarFooterReusableView: UICollectionReusableView { setUp() } + open override var accessibilityElements: [Any]? { + get { + return [containerView, legendLabels] + } + set { super.accessibilityElements = newValue } + } + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- @@ -94,6 +104,7 @@ class CalendarFooterReusableView: UICollectionReusableView { func update(with surface: Surface, indicators: [CalendarBase.CalendarIndicatorModel]) { self.items = indicators self.surface = surface + legendLabels.removeAll() legendCollectionView.reloadData() var height = legendCollectionView.collectionViewLayout.collectionViewContentSize.height @@ -124,6 +135,7 @@ extension CalendarFooterReusableView: UICollectionViewDelegate, UICollectionView surface: self.surface, clearFullcircle: indexPath.row == 1, drawSemiCircle: indexPath.row == 2) + legendLabels.append(cell.title) return cell } @@ -144,12 +156,12 @@ private class LegendCollectionViewCell: UICollectionViewCell { private let indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) - private var title: Label = Label().with { + open var title: Label = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.textAlignment = .left $0.numberOfLines = 1 $0.textStyle = .bodySmall - $0.isAccessibilityElement = false + $0.isAccessibilityElement = true $0.backgroundColor = .clear } diff --git a/VDS/Components/Calendar/CalendarHeaderReusableView.swift b/VDS/Components/Calendar/CalendarHeaderReusableView.swift index d0f7f247..f9c8395d 100644 --- a/VDS/Components/Calendar/CalendarHeaderReusableView.swift +++ b/VDS/Components/Calendar/CalendarHeaderReusableView.swift @@ -86,7 +86,7 @@ class CalendarHeaderReusableView: UICollectionReusableView { $0.numberOfLines = 1 $0.textStyle = .boldBodySmall $0.backgroundColor = .clear - $0.isAccessibilityElement = false + $0.isAccessibilityElement = true } internal let daysOfWeek = Date.capitalizedFirstLettersOfWeekdays @@ -212,7 +212,7 @@ private class collectionViewCell: UICollectionViewCell { $0.numberOfLines = 1 $0.textStyle = .bodySmall $0.backgroundColor = .clear - $0.isAccessibilityElement = false + $0.isAccessibilityElement = true } //-------------------------------------------------- diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index e169cccf..7a158ff6 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -186,8 +186,11 @@ open class DatePicker: EntryFieldBase, DatePickerViewControllerDelegate, UIPopov internal func didSelectDate(_ controller: DatePickerViewController, date: Date) { selectedDate = date - controller.dismiss(animated: true) - sendActions(for: .valueChanged) + controller.dismiss(animated: true) { [weak self] in + guard let self else { return } + self.sendActions(for: .valueChanged) + UIAccessibility.post(notification: .layoutChanged, argument: self.fieldStackView) + } } public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 54007c5a..bad62536 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -148,7 +148,7 @@ open class DropdownSelect: EntryFieldBase { optionsPicker.isHidden = true dropdownField.inputView = optionsPicker dropdownField.inputAccessoryView = { - let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) + let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: containerSize.height))) accessView.backgroundColor = .white accessView.addBorder(side: .top, width: 1, color: .lightGray) let done = UIButton(type: .system) @@ -168,6 +168,7 @@ open class DropdownSelect: EntryFieldBase { self?.launchPicker() } .store(in: &subscribers) + containerView.height(44) } open override func getFieldContainer() -> UIView { @@ -267,7 +268,7 @@ open class DropdownSelect: EntryFieldBase { open override func updateErrorLabel() { super.updateErrorLabel() - if !showError && !hasInternalError { + if !showError && !hasInternalError || !optionsPicker.isHidden { statusIcon.name = .downCaret } statusIcon.surface = surface @@ -348,6 +349,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { } optionsPicker.isHidden = !optionsPicker.isHidden updateContainerView() + updateErrorLabel() } public func numberOfComponents(in pickerView: UIPickerView) -> Int { diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index febb12ca..9e4dd18e 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -141,7 +141,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { setNeedsUpdate() } } - + ///AttributedText that will be used in the label. override open var attributedText: NSAttributedString? { didSet { @@ -169,7 +169,16 @@ open class Label: UILabel, ViewProtocol, UserInfoable { } /// Whether the View is enabled or not. - open override var isEnabled: Bool { didSet { setNeedsUpdate() } } + /// Since the UILabel itselfs draws a different color for the "disabled state", I have to track + /// local variable to deal with color and always enforce this UILabel is always enabled. + private var _fakeIsEnabled: Bool = true + open override var isEnabled: Bool { + get { true } + set { + _fakeIsEnabled = newValue + setNeedsUpdate() + } + } //-------------------------------------------------- // MARK: - Configuration Properties @@ -282,7 +291,21 @@ open class Label: UILabel, ViewProtocol, UserInfoable { styleAttributedText(attributedText) } } - + + + private struct FakeEnabled: Enabling, Surfaceable { + var surface: Surface + var isEnabled: Bool + } + + /// Var to deal with the UILabel.isEnabled property causing issues with + /// textColor when it is false, I am now using a struct to draw and manage + /// colors instead of this class itself and this class will always be enabled + private var _textColor: UIColor { + let fake = FakeEnabled(surface: surface, isEnabled: _fakeIsEnabled) + return textColorConfiguration.getColor(fake) + } + private func styleText(_ newValue: String!) { defer { invalidateIntrinsicContentSize() } guard let newValue, !newValue.isEmpty else { @@ -293,15 +316,13 @@ open class Label: UILabel, ViewProtocol, UserInfoable { } accessibilityCustomActions = [] - //create the primary string let mutableText = NSMutableAttributedString.mutableText(for: newValue, textStyle: textStyle, useScaledFont: useScaledFont, - textColor: textColorConfiguration.getColor(self), + textColor: _textColor, alignment: textAlignment, lineBreakMode: lineBreakMode) - applyAttributes(mutableText) // Set attributed text to match typography diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 8cedb2f8..30df7699 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -101,6 +101,14 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { /// This is set by a local method. internal var bottomContainerView: UIView! + internal var containerBackgroundColor: UIColor { + if showError || hasInternalError { + return backgroundColorConfiguration.getColor(self) + } else { + return transparentBackground ? .clear : backgroundColorConfiguration.getColor(self) + } + } + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -139,7 +147,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: [.focused, .error]) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) + $0.setSurfaceColors(VDSFormControlsColor.borderReadonlyOnlight, VDSFormControlsColor.borderReadonlyOndark, forState: .readonly) } internal let iconColorConfiguration = ControlColorConfiguration().with { @@ -192,8 +200,13 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open override var state: UIControl.State { get { var state = super.state - if showError || hasInternalError { - state.insert(.error) + if isEnabled { + if !isReadOnly && (showError || hasInternalError){ + state.insert(.error) + } + if isReadOnly { + state.insert(.readonly) + } } return state } @@ -436,7 +449,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } internal func updateContainerView() { - containerView.backgroundColor = backgroundColorConfiguration.getColor(self) + containerView.backgroundColor = containerBackgroundColor containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor containerView.layer.borderWidth = VDSFormControls.borderWidth containerView.layer.cornerRadius = VDSFormControls.borderRadius diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 70c6ecd0..76cdaa2a 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -34,6 +34,14 @@ open class InputField: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal override var containerBackgroundColor: UIColor { + if showSuccess { + return backgroundColorConfiguration.getColor(self) + } else { + return super.containerBackgroundColor + } + } + internal override var minWidth: CGFloat { fieldType.handler().minWidth } internal override var maxWidth: CGFloat { let frameWidth = frame.size.width diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index f03300d1..870cf6b6 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -163,9 +163,6 @@ open class TextArea: EntryFieldBase { textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) textViewHeightConstraint?.isActive = true - backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) - borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) - borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .focused) characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() bottomContainerStackView.spacing = VDSLayout.space2X @@ -190,11 +187,7 @@ open class TextArea: EntryFieldBase { textViewHeightConstraint?.constant = minHeight.value characterCounterLabel.text = getCharacterCounterText() - - statusIcon.color = iconColorConfiguration.getColor(self) - containerView.layer.borderColor = isReadOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor textView.isEditable = !isEnabled || isReadOnly ? false : true - textView.backgroundColor = backgroundColorConfiguration.getColor(self) textView.tintColor = iconColorConfiguration.getColor(self) characterCounterLabel.surface = surface highlightCharacterOverflow() diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index ffd16496..7abac288 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -341,6 +341,10 @@ open class TileContainerBase: Control where Padding super.updateAccessibility() containerView.isAccessibilityElement = onClickSubscriber != nil containerView.accessibilityHint = "Double tap to open." + containerView.accessibilityLabel = nil + if let views = accessibilityElements?.compactMap({ $0 as? UIView }), !views.isEmpty { + containerView.setAccessibilityLabel(for: views) + } } open override var accessibilityElements: [Any]? { diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 9d67a6a3..e905560c 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -535,7 +535,6 @@ open class Tilelet: TileContainerBase { descriptiveIcon.colorConfiguration = descriptiveIconModel.colorConfiguration descriptiveIcon.size = descriptiveIconModel.size descriptiveIcon.surface = backgroundColorSurface - descriptiveIcon.accessibilityLabel = descriptiveIconModel.accessibleText showIconContainerView = true } @@ -544,7 +543,6 @@ open class Tilelet: TileContainerBase { directionalIcon.colorConfiguration = directionalIconModel.colorConfiguration directionalIcon.size = directionalIconModel.size.value directionalIcon.surface = backgroundColorSurface - directionalIcon.accessibilityLabel = directionalIconModel.accessibleText showIconContainerView = true } diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index a838c3b9..af52915a 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -274,6 +274,7 @@ open class TitleLockup: View { if subTitleModel != nil { elements.append(subTitleLabel) } + setAccessibilityLabel(for: elements.compactMap({$0 as? UIView})) accessibilityElements = elements.count > 0 ? elements : nil } diff --git a/VDS/Extensions/UIControl.swift b/VDS/Extensions/UIControl.swift index e978bed9..761e502d 100644 --- a/VDS/Extensions/UIControl.swift +++ b/VDS/Extensions/UIControl.swift @@ -15,4 +15,7 @@ extension UIControl.State { /// State for Success public static var success = UIControl.State(rawValue: 1 << 17) + + /// State for Success + public static var readonly = UIControl.State(rawValue: 1 << 18) } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index ac767368..265c65ba 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,8 +1,12 @@ 1.0.65 ---------------- - CXTDT-556996 - RadioboxGroup – Accessibility - Voice over does not render the group position -- CXTDT-560458 - Dropdown & TextArea voiceover behaviour +- CXTDT-560458 - Dropdown / TextArea - Accessibility - CXTDT-560485 - Tilelet - Accessibility +- CXTDT-559318 - Calendar - Accessibility +- CXTDT-563189 - Dropdown Select Readonly Border color +- CXTDT-555854 - Dropdown Select - spacing issues +- CXTDT-563194 - Dropdown Select - missing transparentBackground option 1.0.64 ----------------