Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/vds_ios into feature/Table
This commit is contained in:
commit
a82550ed57
@ -1393,7 +1393,7 @@
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 59;
|
||||
CURRENT_PROJECT_VERSION = 60;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@ -1430,7 +1430,7 @@
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 59;
|
||||
CURRENT_PROJECT_VERSION = 60;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
||||
@ -35,13 +35,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
|
||||
//--------------------------------------------------
|
||||
open var subscribers = Set<AnyCancellable>()
|
||||
|
||||
open var onClickSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onClickSubscriber {
|
||||
onClickSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onClickSubscriber: AnyCancellable?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
@ -118,6 +112,8 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
|
||||
backgroundColor = .clear
|
||||
surface = .light
|
||||
isEnabled = true
|
||||
onClick = nil
|
||||
userInfo.removeAll()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -47,13 +47,7 @@ open class SelectorBase: Control, SelectorControlable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
open var size = CGSize(width: 20, height: 20) { didSet { setNeedsUpdate() } }
|
||||
|
||||
@ -120,19 +114,23 @@ open class SelectorBase: Control, SelectorControlable {
|
||||
accessibilityTraits = .button
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
|
||||
/// Used to update any Accessibility properties.ß
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
accessibilityLabel = "\(Self.self)\(showError ? ", error" : "")"
|
||||
}
|
||||
|
||||
/// This will change the state of the Selector and execute the actionBlock if provided.
|
||||
open func toggle() { }
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
onChange = nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,13 +75,7 @@ open class SelectorGroupBase<SelectorItemType: Control>: Control, SelectorGroup,
|
||||
}
|
||||
}
|
||||
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
/// Whether the Control is enabled or not.
|
||||
override open var isEnabled: Bool {
|
||||
@ -130,6 +124,7 @@ open class SelectorGroupBase<SelectorItemType: Control>: Control, SelectorGroup,
|
||||
/// Resets to default settings.
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
onChange = nil
|
||||
items.forEach{ $0.reset() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,13 +61,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
/// Label used to render labelText.
|
||||
open var label = Label().with {
|
||||
@ -196,7 +190,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
|
||||
/// Used to update any Accessibility properties.
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
setAccessibilityLabel(for: [label, childLabel, errorLabel])
|
||||
setAccessibilityLabel(for: [selectorView, label, childLabel, errorLabel])
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
@ -223,6 +217,7 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
|
||||
value = nil
|
||||
isSelected = false
|
||||
|
||||
onChange = nil
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
@ -344,7 +344,6 @@ open class BadgeIndicator: View {
|
||||
label.isEnabled = isEnabled
|
||||
label.sizeToFit()
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
open override func updateAccessibility() {
|
||||
|
||||
@ -84,7 +84,7 @@ final class BreadcrumbCellItem: UICollectionViewCell {
|
||||
separator.textColor = textColorConfiguration.getColor(surface)
|
||||
separator.isHidden = hideSlash
|
||||
self.breadCrumbItem = breadCrumbItem
|
||||
layoutIfNeeded()
|
||||
setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -38,13 +38,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
|
||||
/// Set of Subscribers for any Publishers for this Control.
|
||||
open var subscribers = Set<AnyCancellable>()
|
||||
|
||||
open var onClickSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onClickSubscriber {
|
||||
onClickSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onClickSubscriber: AnyCancellable?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
@ -140,6 +134,8 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
|
||||
isEnabled = true
|
||||
text = nil
|
||||
accessibilityCustomActions = []
|
||||
onClick = nil
|
||||
userInfo.removeAll()
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
@ -42,7 +42,6 @@ open class Checkbox: SelectorBase {
|
||||
/// 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 = "Checkbox"
|
||||
|
||||
backgroundColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected)
|
||||
backgroundColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: [.selected, .highlighted])
|
||||
@ -71,7 +70,7 @@ open class Checkbox: SelectorBase {
|
||||
isSelected.toggle()
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
|
||||
@ -109,7 +109,8 @@ open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
///Badge Indicator object used to render for the ButtonIcon.
|
||||
open var badgeIndicator = BadgeIndicator().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -172,8 +173,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||
/// Used to move the icon inside the button in both x and y axis.
|
||||
open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
open var inputId: String? { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var value: AnyHashable? { didSet { setNeedsUpdate() } }
|
||||
@ -365,7 +364,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
isAccessibilityElement = false
|
||||
accessibilityElements = [icon, badgeIndicator]
|
||||
|
||||
//create a layoutGuide for the icon to key off of
|
||||
let iconLayoutGuide = UILayoutGuide()
|
||||
@ -436,6 +434,7 @@ open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||
showBadgeIndicator = false
|
||||
selectable = false
|
||||
badgeIndicatorModel = nil
|
||||
onChange = nil
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
@ -459,6 +458,18 @@ open class ButtonIcon: Control, Changeable, FormFieldable {
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
var elements = [Any]()
|
||||
if iconName != nil {
|
||||
elements.append(icon)
|
||||
}
|
||||
if badgeIndicatorModel != nil && showBadgeIndicator {
|
||||
elements.append(badgeIndicator)
|
||||
}
|
||||
accessibilityElements = elements.count > 0 ? elements : nil
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
|
||||
@ -31,12 +31,13 @@ public struct ColorLabelAttribute: LabelAttributeModel {
|
||||
}
|
||||
|
||||
public func setAttribute(on attributedString: NSMutableAttributedString) {
|
||||
guard isValidRange(on: attributedString) else { return }
|
||||
|
||||
var colorRange = range
|
||||
if length == 0 && location == 0 {
|
||||
colorRange = .init(location: location, length: attributedString.length)
|
||||
}
|
||||
|
||||
if !attributedString.isValid(range: colorRange) { return }
|
||||
|
||||
let attributeKey = isForegroundColor ? NSAttributedString.Key.foregroundColor : NSAttributedString.Key.backgroundColor
|
||||
attributedString.removeAttribute(attributeKey, range: colorRange)
|
||||
attributedString.addAttribute(attributeKey, value: color, range: colorRange)
|
||||
|
||||
@ -230,7 +230,6 @@ open class Label: UILabel, ViewProtocol, UserInfoable {
|
||||
setNeedsDisplay()
|
||||
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
open func updateAccessibility() {
|
||||
|
||||
@ -264,8 +264,6 @@ open class Notification: View {
|
||||
isAccessibilityElement = false
|
||||
accessibilityElements = [closeButton, typeIcon, titleLabel, subTitleLabel, buttonGroup]
|
||||
closeButton.accessibilityTraits = [.button]
|
||||
closeButton.accessibilityLabel = "Close Notification"
|
||||
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
@ -325,7 +323,6 @@ open class Notification: View {
|
||||
let iconColor = surface == .dark ? VDSColor.paletteWhite : VDSColor.paletteBlack
|
||||
typeIcon.name = style.iconName
|
||||
typeIcon.color = iconColor
|
||||
typeIcon.accessibilityLabel = style.accessibilityText
|
||||
closeButton.color = iconColor
|
||||
closeButton.isHidden = hideCloseButton
|
||||
}
|
||||
@ -374,6 +371,12 @@ open class Notification: View {
|
||||
}
|
||||
}
|
||||
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
closeButton.accessibilityLabel = "Close Notification"
|
||||
typeIcon.accessibilityLabel = style.accessibilityText
|
||||
}
|
||||
|
||||
private func setConstraints() {
|
||||
labelViewAndButtonViewConstraint?.deactivate()
|
||||
labelViewBottomConstraint?.deactivate()
|
||||
|
||||
@ -174,7 +174,7 @@ open class Pagination: View {
|
||||
let isNextAction = sender == nextButton
|
||||
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
|
||||
updateSelection()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
||||
guard let self else { return }
|
||||
UIAccessibility.post(notification: .announcement, argument: "Page \(self.selectedPage) of \(self.total) selected")
|
||||
}
|
||||
|
||||
@ -78,6 +78,11 @@ open class PaginationButton: ButtonBase {
|
||||
tintColor = color
|
||||
super.updateView()
|
||||
}
|
||||
|
||||
open override func accessibilityActivate() -> Bool {
|
||||
sendActions(for: .touchUpInside)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension PaginationButton {
|
||||
|
||||
@ -49,6 +49,8 @@ open class RadioBoxGroup: SelectorGroupBase<RadioBoxItem>, SelectorGroupSingleSe
|
||||
$0.isEnabled = !model.disabled
|
||||
$0.inputId = model.inputId
|
||||
$0.isSelected = model.selected
|
||||
$0.strikethrough = model.strikethrough
|
||||
$0.strikethroughAccessibilityText = model.strikethroughAccessibileText
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,12 +117,14 @@ extension RadioBoxGroup {
|
||||
/// Array of LabelAttributeModel objects used in rendering the subTextRight.
|
||||
public var subTextRightAttributes: [any LabelAttributeModel]?
|
||||
public var selected: Bool
|
||||
public var strikethrough: Bool = false
|
||||
public var strikethroughAccessibileText: String
|
||||
|
||||
public init(disabled: Bool, surface: Surface = .light, inputId: String? = nil, value: AnyHashable? = nil,
|
||||
text: String = "", textAttributes: [any LabelAttributeModel]? = nil,
|
||||
subText: String? = nil, subTextAttributes: [any LabelAttributeModel]? = nil,
|
||||
subTextRight: String? = nil, subTextRightAttributes: [any LabelAttributeModel]? = nil,
|
||||
selected: Bool = false, errorText: String? = nil, accessibileText: String? = nil) {
|
||||
selected: Bool = false, errorText: String? = nil, accessibileText: String? = nil, strikethrough: Bool = false, strikethroughAccessibileText: String = "not available") {
|
||||
self.disabled = disabled
|
||||
self.surface = surface
|
||||
self.inputId = inputId
|
||||
@ -133,6 +137,8 @@ extension RadioBoxGroup {
|
||||
self.subTextRightAttributes = subTextRightAttributes
|
||||
self.selected = selected
|
||||
self.accessibileText = accessibileText
|
||||
self.strikethrough = strikethrough
|
||||
self.strikethroughAccessibileText = strikethroughAccessibileText
|
||||
}
|
||||
|
||||
public init() {
|
||||
|
||||
@ -38,7 +38,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
$0.alignment = .top
|
||||
$0.distribution = .fill
|
||||
$0.axis = .horizontal
|
||||
$0.spacing = 12
|
||||
$0.spacing = VDSLayout.space3X
|
||||
}
|
||||
|
||||
private var selectorLeftLabelStackView = UIStackView().with {
|
||||
@ -52,13 +52,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
/// Label used to render the text.
|
||||
open var textLabel = Label().with {
|
||||
@ -129,6 +123,8 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
/// If provided, the radio box will be rendered to show the option with a strikethrough.
|
||||
open var strikethrough: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var strikethroughAccessibilityText: String = "not available" { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var inputId: String? { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var value: AnyHashable? { didSet { setNeedsUpdate() } }
|
||||
@ -189,7 +185,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
.pinTrailing(0, .defaultHigh)
|
||||
.pinBottom(0, .defaultHigh)
|
||||
|
||||
selectorStackView.pinToSuperView(.uniform(16))
|
||||
selectorStackView.pinToSuperView(.uniform(VDSLayout.space3X))
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
@ -218,6 +214,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
value = nil
|
||||
|
||||
isSelected = false
|
||||
onChange = nil
|
||||
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
@ -236,15 +233,13 @@ open class RadioBoxItem: Control, Changeable, FormFieldable {
|
||||
|
||||
updateLabels()
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
/// Used to update any Accessibility properties.
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
if accessibilityLabel == nil {
|
||||
setAccessibilityLabel(for: [textLabel, subTextLabel, subTextRightLabel])
|
||||
}
|
||||
setAccessibilityLabel(for: [textLabel, subTextLabel, subTextRightLabel])
|
||||
accessibilityValue = strikethrough ? strikethroughAccessibilityText : nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -172,7 +172,6 @@ extension Tabs {
|
||||
label.textAlignment = textAlignment.value
|
||||
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
/// Used to update any Accessibility properties.
|
||||
|
||||
@ -119,13 +119,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
open var titleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
@ -135,6 +129,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
open var errorLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textStyle = .bodySmall
|
||||
$0.accessibilityValue = "error"
|
||||
}
|
||||
|
||||
open var helperLabel = Label().with {
|
||||
@ -304,6 +299,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
defaultValue = nil
|
||||
required = false
|
||||
readOnly = false
|
||||
onChange = nil
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
|
||||
@ -151,7 +151,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate {
|
||||
/// 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
|
||||
|
||||
@ -272,6 +273,25 @@ open class InputField: EntryFieldBase, UITextFieldDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to update any Accessibility properties.
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
textField.accessibilityLabel = showError ? "error" : nil
|
||||
if showError {
|
||||
accessibilityElements = [titleLabel, textField, icon, errorLabel, helperLabel]
|
||||
} else {
|
||||
accessibilityElements = [titleLabel, textField, helperLabel]
|
||||
}
|
||||
}
|
||||
|
||||
open override var canBecomeFirstResponder: Bool { true }
|
||||
|
||||
open override func resignFirstResponder() -> Bool {
|
||||
if textField.isFirstResponder {
|
||||
textField.resignFirstResponder()
|
||||
}
|
||||
return super.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
extension InputField.FieldType {
|
||||
|
||||
@ -239,6 +239,7 @@ open class TextArea: EntryFieldBase {
|
||||
/// Used to update any Accessibility properties.
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
textView.accessibilityLabel = showError ? "error" : nil
|
||||
if showError {
|
||||
accessibilityElements = [titleLabel, textView, icon, errorLabel, helperLabel]
|
||||
} else {
|
||||
@ -246,6 +247,15 @@ open class TextArea: EntryFieldBase {
|
||||
}
|
||||
}
|
||||
|
||||
open override var canBecomeFirstResponder: Bool { true }
|
||||
|
||||
open override func resignFirstResponder() -> Bool {
|
||||
if textView.isFirstResponder {
|
||||
textView.resignFirstResponder()
|
||||
}
|
||||
return super.resignFirstResponder()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -147,5 +147,6 @@ open class TextView: UITextView, ViewProtocol {
|
||||
attributedText = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
import Foundation
|
||||
import VDSTokens
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
@objc(VDSTileContainer)
|
||||
open class TileContainer: TileContainerBase<TileContainer.Padding> {
|
||||
@ -43,7 +44,6 @@ open class TileContainer: TileContainerBase<TileContainer.Padding> {
|
||||
}
|
||||
|
||||
open class TileContainerBase<PaddingType: DefaultValuing>: Control where PaddingType.ValueType == CGFloat {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
@ -111,6 +111,19 @@ open class TileContainerBase<PaddingType: DefaultValuing>: 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() } }
|
||||
|
||||
@ -171,7 +184,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
|
||||
open var showBorder: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Determines if there is a drop shadow or not.
|
||||
open var showDropShadows: Bool = false { didSet { setNeedsUpdate() } }
|
||||
open var showDropShadow: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
@ -274,7 +287,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
|
||||
width = nil
|
||||
height = nil
|
||||
showBorder = false
|
||||
showDropShadows = false
|
||||
showDropShadow = false
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
@ -316,12 +329,14 @@ open class TileContainerBase<PaddingType: DefaultValuing>: Control where Padding
|
||||
widthConstraint?.isActive = false
|
||||
heightConstraint?.isActive = false
|
||||
}
|
||||
if showDropShadows, surface == .light {
|
||||
|
||||
applyBackgroundEffects()
|
||||
|
||||
if showDropShadow, surface == .light {
|
||||
addDropShadow(dropShadowConfiguration)
|
||||
} else {
|
||||
removeDropShadows()
|
||||
}
|
||||
applyBackgroundEffects()
|
||||
}
|
||||
|
||||
/// Used to update frames for the added CAlayers to our view
|
||||
@ -337,6 +352,7 @@ open class TileContainerBase<PaddingType: DefaultValuing>: 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)
|
||||
if shouldPin {
|
||||
view.pinToSuperView()
|
||||
|
||||
@ -22,7 +22,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
public enum Padding: String, DefaultValuing, CaseIterable {
|
||||
case small
|
||||
case large
|
||||
|
||||
|
||||
public static var defaultValue: Self { .large }
|
||||
|
||||
public var value: CGFloat {
|
||||
@ -63,7 +63,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
@ -105,12 +105,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public override var onClickSubscriber: AnyCancellable? {
|
||||
didSet {
|
||||
isAccessibilityElement = onClickSubscriber != nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Title lockup positioned in the contentView.
|
||||
open var titleLockup = TitleLockup().with {
|
||||
$0.standardStyleConfiguration = .init(styleConfigurations: [
|
||||
@ -213,7 +207,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
open var directionalIcon = Icon().with {
|
||||
$0.name = .rightArrow
|
||||
}
|
||||
|
||||
|
||||
private var _textWidth: TextWidth?
|
||||
|
||||
/// If provided, width of Button components will be rendered based on this value. If omitted, default button widths are rendered.
|
||||
@ -276,7 +270,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
_descriptiveIconModel = nil
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
@ -294,7 +288,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
internal var titleLockupEyebrowLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupTitleLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupSubTitleLabelHeightGreaterThanConstraint: NSLayoutConstraint?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
@ -305,9 +299,6 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
color = .black
|
||||
addContentView(stackView)
|
||||
|
||||
accessibilityTraits = .link
|
||||
accessibilityElements = [badge, titleLockup, descriptiveIcon, directionalIcon]
|
||||
|
||||
//badge
|
||||
badgeContainerView.addSubview(badge)
|
||||
badge
|
||||
@ -328,7 +319,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
titleLockupBottomGreaterThanConstraint = titleLockupContainerView.bottomAnchor.constraint(greaterThanOrEqualTo: titleLockup.bottomAnchor)
|
||||
titleLockupTopGreaterThanConstraint = titleLockup.topAnchor.constraint(greaterThanOrEqualTo: titleLockupContainerView.topAnchor)
|
||||
titleLockupCenterYConstraint = titleLockup.centerYAnchor.constraint(equalTo: titleLockupContainerView.centerYAnchor)
|
||||
|
||||
|
||||
iconContainerView.addSubview(descriptiveIcon)
|
||||
iconContainerView.addSubview(directionalIcon)
|
||||
|
||||
@ -357,12 +348,12 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
badge.label.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-1), for: .vertical)
|
||||
titleLockup.subTitleLabel.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-2), for: .vertical)
|
||||
titleLockup.eyebrowLabel.setContentCompressionResistancePriority(UILayoutPriority(labelPriority-3), for: .vertical)
|
||||
|
||||
|
||||
titleLockup.titleLabel.setContentHuggingPriority(UILayoutPriority(labelPriority), for: .vertical)
|
||||
badge.label.setContentHuggingPriority(UILayoutPriority(labelPriority-1), for: .vertical)
|
||||
titleLockup.subTitleLabel.setContentHuggingPriority(UILayoutPriority(labelPriority-2), for: .vertical)
|
||||
titleLockup.eyebrowLabel.setContentHuggingPriority(UILayoutPriority(labelPriority-3), for: .vertical)
|
||||
|
||||
|
||||
/**
|
||||
Added these constraints for:
|
||||
At fixed width & height if all the labels(Badge, Eyebrow, Title, Subtitle) are having more number of lines then we should display atleast one line of content per label instead of pushing labels out of bounds.
|
||||
@ -412,13 +403,27 @@ open class Tilelet: TileContainerBase<Tilelet.Padding> {
|
||||
if width != nil && (aspectRatio != .none || height != nil) {
|
||||
updateTextPositionAlignment()
|
||||
}
|
||||
layoutIfNeeded()
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
/// Used to update any Accessibility properties.
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
|
||||
var elements = [Any]()
|
||||
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)
|
||||
}
|
||||
accessibilityElements = elements.count > 0 ? elements : nil
|
||||
|
||||
setAccessibilityLabel(for: [badge.label, titleLockup.eyebrowLabel, titleLockup.titleLabel, titleLockup.subTitleLabel])
|
||||
}
|
||||
|
||||
|
||||
@ -272,7 +272,21 @@ open class TitleLockup: View {
|
||||
|
||||
titleLabel.textColorConfiguration = textColorPrimaryConfiguration
|
||||
|
||||
accessibilityElements = [eyebrowLabel, titleLabel, subTitleLabel]
|
||||
}
|
||||
|
||||
open override func updateAccessibility() {
|
||||
super.updateAccessibility()
|
||||
var elements = [Any]()
|
||||
if eyebrowModel != nil {
|
||||
elements.append(eyebrowLabel)
|
||||
}
|
||||
if titleModel != nil {
|
||||
elements.append(titleLabel)
|
||||
}
|
||||
if subTitleModel != nil {
|
||||
elements.append(subTitleLabel)
|
||||
}
|
||||
accessibilityElements = elements.count > 0 ? elements : nil
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
|
||||
@ -88,13 +88,7 @@ open class Toggle: Control, Changeable, FormFieldable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
open var onChangeSubscriber: AnyCancellable?
|
||||
|
||||
/// Actual toggle used in this component.
|
||||
open var toggleView = ToggleView().with {
|
||||
@ -231,6 +225,7 @@ open class Toggle: Control, Changeable, FormFieldable {
|
||||
textPosition = .left
|
||||
inputId = nil
|
||||
value = nil
|
||||
onChange = nil
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
@ -166,6 +166,7 @@ open class ToggleView: Control, Changeable, FormFieldable {
|
||||
value = nil
|
||||
toggleView.backgroundColor = toggleColorConfiguration.getColor(self)
|
||||
knobView.backgroundColor = knobColorConfiguration.getColor(self)
|
||||
onChange = nil
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
@ -227,7 +228,6 @@ open class ToggleView: Control, Changeable, FormFieldable {
|
||||
knobTrailingConstraint?.isActive = true
|
||||
knobLeadingConstraint?.isActive = true
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
private func updateToggle() {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
import Foundation
|
||||
|
||||
extension DispatchQueue {
|
||||
private static var _onceTracker = [String]()
|
||||
private static var _onceTracker = Set<String>()
|
||||
|
||||
public class func once(
|
||||
file: String = #file,
|
||||
@ -31,12 +31,17 @@ extension DispatchQueue {
|
||||
token: String,
|
||||
block: () -> Void
|
||||
) {
|
||||
// Peek ahead to avoid the intersection.
|
||||
guard !_onceTracker.contains(token) else { return }
|
||||
|
||||
objc_sync_enter(self)
|
||||
defer { objc_sync_exit(self) }
|
||||
|
||||
// Double check we are the first in the critical section.
|
||||
guard !_onceTracker.contains(token) else { return }
|
||||
|
||||
_onceTracker.append(token)
|
||||
// Execute.
|
||||
_onceTracker.insert(token)
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,8 @@ extension Changeable {
|
||||
.sink { c in
|
||||
newValue(c)
|
||||
}
|
||||
} else {
|
||||
onChangeSubscriber = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ extension Clickable {
|
||||
public var onClick: ((Self) -> ())? {
|
||||
get { return nil }
|
||||
set {
|
||||
onClickSubscriber?.cancel()
|
||||
if let newValue {
|
||||
onClickSubscriber = publisher(for: .touchUpInside)
|
||||
.sink { [weak self] c in
|
||||
@ -27,7 +28,6 @@ extension Clickable {
|
||||
newValue(c)
|
||||
}
|
||||
} else {
|
||||
onClickSubscriber?.cancel()
|
||||
onClickSubscriber = nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,10 @@
|
||||
- CXTDT-544442 - Button Icon - Selected state needs to allow custom color
|
||||
- CXTDT-546821 - TextArea - Accessibility - input field is not receiving swipe focus
|
||||
- CXTDT-547200 - Carousel scrollbar – Accessibility - The scrollbar is receiving right/ left swipe focus
|
||||
- CXTDT-549888 - Pagination - Accessibility - Next/Previous
|
||||
- CXTDT-542333 - RadioBox Padding
|
||||
- CXTDT-549901 - RadioBox strike through state
|
||||
- CXTDT-546824 - Notification - Accessibility - Improper label for close notification button & icon
|
||||
|
||||
1.0.59
|
||||
----------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user