diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index bdf19831..d32c1169 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -111,27 +111,19 @@ open class TileContainerBase: Control where Padding //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var onClickSubscriber: AnyCancellable? { - didSet { - if onClickSubscriber != nil { - isAccessibilityElement = true - accessibilityTraits = .link - accessibilityHint = "Double tap to open." - } else { - isAccessibilityElement = false - accessibilityTraits.remove(.link) - } - } - } - /// This takes an image source url and applies it as a background image. open var backgroundImage: UIImage? { didSet { setNeedsUpdate() } } + /// This is the container in which views will be pinned. + open var contentView = View().with { + $0.isUserInteractionEnabled = false + } + /// This is the container in which views will be pinned. open var containerView = View().with { $0.isUserInteractionEnabled = false } - + /// This is the view used to show the high light color for a onClick. open var highlightView = View().with { $0.isUserInteractionEnabled = false @@ -232,6 +224,7 @@ open class TileContainerBase: Control where Padding /// 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 let layoutGuide = UILayoutGuide() addLayoutGuide(layoutGuide) @@ -240,11 +233,13 @@ open class TileContainerBase: Control where Padding .pinLeading() .pinTrailing(0, .defaultHigh) .pinBottom(0, .defaultHigh) - addSubview(backgroundImageView) addSubview(containerView) + containerView.addSubview(contentView) addSubview(highlightView) - + + containerView.pinToSuperView() + widthConstraint = layoutGuide.widthAnchor.constraint(equalToConstant: 0) heightGreaterThanConstraint = layoutGuide.heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0) @@ -253,7 +248,7 @@ open class TileContainerBase: Control where Padding heightConstraint = layoutGuide.heightAnchor.constraint(equalToConstant: 0) backgroundImageView.pinToSuperView() - + backgroundImageView.setContentHuggingPriority(.defaultLow, for: .horizontal) backgroundImageView.setContentHuggingPriority(.defaultLow, for: .vertical) backgroundImageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) @@ -261,10 +256,10 @@ open class TileContainerBase: Control where Padding backgroundImageView.isUserInteractionEnabled = false backgroundImageView.isHidden = true - containerTopConstraint = containerView.pinTop(anchor: layoutGuide.topAnchor, constant: padding.value) - containerBottomConstraint = layoutGuide.pinBottom(anchor: containerView.bottomAnchor, constant: padding.value) - containerLeadingConstraint = containerView.pinLeading(anchor: layoutGuide.leadingAnchor, constant: padding.value) - containerTrailingConstraint = layoutGuide.pinTrailing(anchor: containerView.trailingAnchor, constant: padding.value) + containerTopConstraint = contentView.pinTop(anchor: layoutGuide.topAnchor, constant: padding.value) + containerBottomConstraint = layoutGuide.pinBottom(anchor: contentView.bottomAnchor, constant: padding.value) + containerLeadingConstraint = contentView.pinLeading(anchor: layoutGuide.leadingAnchor, constant: padding.value) + containerTrailingConstraint = layoutGuide.pinTrailing(anchor: contentView.trailingAnchor, constant: padding.value) highlightView.pin(layoutGuide) highlightView.isHidden = true @@ -291,7 +286,7 @@ open class TileContainerBase: Control where Padding shouldUpdateView = true setNeedsUpdate() } - + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -339,6 +334,30 @@ open class TileContainerBase: Control where Padding } } + open override func updateAccessibility() { + super.updateAccessibility() + containerView.isAccessibilityElement = onClickSubscriber != nil + containerView.accessibilityHint = "Double tap to open." + } + + open override var accessibilityElements: [Any]? { + get { + var items = [Any]() + if containerView.isAccessibilityElement { + if !accessibilityTraits.contains(.button) && !accessibilityTraits.contains(.link) { + containerView.accessibilityTraits = .button + } else { + containerView.accessibilityTraits = accessibilityTraits + } + items.append(containerView) + } + items.append(contentsOf: contentView.subviews.filter({ $0.isAccessibilityElement == true })) + return items + } + + set {} + } + /// Used to update frames for the added CAlayers to our view open override func layoutSubviews() { super.layoutSubviews() @@ -353,7 +372,7 @@ open class TileContainerBase: Control where Padding /// This will place a view within the contentView of this component. public func addContentView(_ view: UIView, shouldPin: Bool = true) { view.removeFromSuperview() - containerView.addSubview(view) + contentView.addSubview(view) if shouldPin { view.pinToSuperView() } diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index fb0e5cf8..fe9fe7f1 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -201,10 +201,13 @@ open class Tilelet: TileContainerBase { } /// Descriptive Icon positioned in the contentView. - open var descriptiveIcon = Icon() + open var descriptiveIcon = Icon().with { + $0.isAccessibilityElement = true + } /// Directional Icon positioned in the contentView. open var directionalIcon = Icon().with { + $0.isAccessibilityElement = true $0.name = .rightArrow } @@ -407,24 +410,30 @@ open class Tilelet: TileContainerBase { } /// Used to update any Accessibility properties. - open override func updateAccessibility() { - super.updateAccessibility() - var elements = [Any]() - if badgeModel != nil { - elements.append(badge) + open override var accessibilityElements: [Any]? { + + get { + var elements = [Any]() + if let superElements = super.accessibilityElements { + elements.append(contentsOf: superElements) + } + if badgeModel != nil { + elements.append(badge) + } + if titleModel != nil || subTitleModel != nil || eyebrowModel != nil { + elements.append(titleLockup) + } + if descriptiveIconModel != nil { + elements.append(descriptiveIcon) + } + if directionalIconModel != nil { + elements.append(directionalIcon) + } + return elements } - if titleModel != nil || subTitleModel != nil || eyebrowModel != nil { - elements.append(titleLockup) - } - if descriptiveIconModel != nil { - elements.append(descriptiveIcon) - } - if directionalIconModel != nil { - elements.append(directionalIcon) - } - accessibilityElements = elements.count > 0 ? elements : nil + + set {} - setAccessibilityLabel(for: [badge.label, titleLockup.eyebrowLabel, titleLockup.titleLabel, titleLockup.subTitleLabel]) } //-------------------------------------------------- @@ -482,7 +491,7 @@ open class Tilelet: TileContainerBase { titleLockupWidthConstraint = NSLayoutConstraint(item: titleLockup, attribute: .width, relatedBy: .equal, - toItem: containerView, + toItem: contentView, attribute: .width, multiplier: percentage / 100, constant: 0.0) @@ -521,12 +530,14 @@ open class Tilelet: TileContainerBase { descriptiveIcon.name = descriptiveIconModel.name descriptiveIcon.size = descriptiveIconModel.size descriptiveIcon.surface = descriptiveIconModel.surface + descriptiveIcon.accessibilityLabel = descriptiveIconModel.accessibleText showIconContainerView = true } if let directionalIconModel { directionalIcon.size = directionalIconModel.size directionalIcon.surface = directionalIconModel.surface + directionalIcon.accessibilityLabel = "Right arrow" showIconContainerView = true } diff --git a/VDS/Components/Tilelet/TileletIconModels.swift b/VDS/Components/Tilelet/TileletIconModels.swift index e3a89a5b..457cd907 100644 --- a/VDS/Components/Tilelet/TileletIconModels.swift +++ b/VDS/Components/Tilelet/TileletIconModels.swift @@ -18,11 +18,15 @@ extension Tilelet { /// Enum for a preset height and width for the icon. public var size: Icon.Size + /// Accessible Text for the Icon + var accessibleText: String + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface - public init(name: Icon.Name = .multipleDocuments, size: Icon.Size = .medium, surface: Surface = .dark) { + public init(name: Icon.Name = .multipleDocuments, size: Icon.Size = .medium, accessibleText: String? = nil, surface: Surface = .dark) { self.name = name + self.accessibleText = accessibleText ?? name.rawValue self.size = size self.surface = surface } diff --git a/VDS/Protocols/Changeable.swift b/VDS/Protocols/Changeable.swift index c44fa841..19fe56fb 100644 --- a/VDS/Protocols/Changeable.swift +++ b/VDS/Protocols/Changeable.swift @@ -29,6 +29,7 @@ extension Changeable { } else { onChangeSubscriber = nil } + setNeedsUpdate() } } } diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index eddcfa3c..c2fc9056 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -30,6 +30,7 @@ extension Clickable { } else { onClickSubscriber = nil } + setNeedsUpdate() } } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 16130503..198d284d 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -6,6 +6,8 @@ - CXTDT-552071 - Text Area - Entering text - CXTDT-552060 - Text Area - Placeholder text - CXTDT-552842 - Breadcrumbs - Accessibility +- CXTDT-552825 - Tilelet - Accessibility – The role of button is not provided for the tilelet. +- CXTDT-552834 - TileContainer - Accessibility – Voice over is not rendering the information present click state. 1.0.60