Merge branch 'mbruce/bugfixes' into 'develop'

fixed bug for trailing tooltip

See merge request BPHV_MIPS/vds_ios!100
This commit is contained in:
Bruce, Matt R 2023-08-02 16:10:19 +00:00
commit 9c358c39ce
29 changed files with 270 additions and 188 deletions

View File

@ -128,12 +128,23 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
/// Update this view based off of property changes
open func updateView() {
updateAccessibilityLabel()
updateAccessibility()
}
/// Used to update any Accessibility properties
open func updateAccessibilityLabel() {
open func updateAccessibility() {
if isSelected {
accessibilityTraits.insert(.selected)
} else {
accessibilityTraits.remove(.selected)
}
if isEnabled {
accessibilityTraits.remove(.notEnabled)
} else {
accessibilityTraits.insert(.notEnabled)
}
}
/// Resets to the Controls default values

View File

@ -88,18 +88,7 @@ open class SelectorBase: Control, SelectorControlable {
layoutIfNeeded()
}
open override func updateAccessibilityLabel() {
accessibilityValue = isSelected ? "1" : "0"
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.remove(.notEnabled)
}
open override func updateAccessibility() {
super.updateAccessibility()
}
}

View File

@ -69,18 +69,8 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
selectorViews.forEach{ $0.reset() }
}
open override func updateAccessibilityLabel() {
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.remove(.notEnabled)
}
open override func updateAccessibility() {
super.updateAccessibility()
setAccessibilityLabel(for: selectorViews)
}
}
@ -92,8 +82,8 @@ open class SelectorGroupSelectedHandlerBase<HandlerType: Control>: SelectorGroup
return selectorViews.filter { $0.isSelected == true }.first
}
open override func updateAccessibilityLabel() {
super.updateAccessibilityLabel()
open override func updateAccessibility() {
super.updateAccessibility()
if let selectedHandler, let value = selectedHandler.accessibilityValue, let label = selectedHandler.accessibilityLabel {
accessibilityValue = "\(label) \(value)"
} else {

View File

@ -267,22 +267,11 @@ open class SelectorItemBase<Selector: SelectorControlable>: Control, Errorable,
selectorView.isHighlighted = isHighlighted
selectorView.disabled = disabled
selectorView.surface = surface
updateAccessibilityLabel()
updateAccessibility()
}
open override func updateAccessibilityLabel() {
accessibilityValue = isSelected ? "1" : "0"
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.remove(.notEnabled)
}
open override func updateAccessibility() {
super.updateAccessibility()
setAccessibilityLabel(for: [label, childLabel, errorLabel])
}
}

View File

@ -82,12 +82,16 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable {
/// Update this view based off of property changes
open func updateView() {
updateAccessibilityLabel()
updateAccessibility()
}
/// Used to update any Accessibility properties
open func updateAccessibilityLabel() {
open func updateAccessibility() {
if isEnabled {
accessibilityTraits.remove(.notEnabled)
} else {
accessibilityTraits.insert(.notEnabled)
}
}
/// Resets to the Views default values

View File

@ -158,14 +158,14 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
open func updateView() {
updateLabel()
updateAccessibilityLabel()
updateAccessibility()
}
open func updateAccessibilityLabel() {
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
open func updateAccessibility() {
if isEnabled {
accessibilityTraits.remove(.notEnabled)
} else {
accessibilityTraits.insert(.notEnabled)
}
}

View File

@ -38,13 +38,14 @@ open class CheckboxGroup: SelectorGroupHandlerBase<CheckboxItem> {
public var selectorModels: [CheckboxModel]? {
didSet {
if let selectorModels {
selectorViews = selectorModels.map { model in
selectorViews = selectorModels.enumerated().map { index, model in
return CheckboxItem().with {
$0.disabled = model.disabled
$0.surface = model.surface
$0.inputId = model.inputId
$0.value = model.value
$0.accessibilityLabel = model.accessibileText
$0.accessibilityValue = "item \(index+1) of \(selectorModels.count)"
$0.labelText = model.labelText
$0.labelTextAttributes = model.labelTextAttributes
$0.childText = model.childText

View File

@ -102,11 +102,7 @@ open class Icon: View {
imageView.image = nil
}
}
public override func updateAccessibilityLabel() {
}
private func getImage(for imageName: String) -> UIImage? {
return BundleManager.shared.image(for: imageName)

View File

@ -23,6 +23,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
public var title: String?
public var content: String?
public var contentView: UIView?
public var presenter: UIView?
public func setAttribute(on attributedString: NSMutableAttributedString) {
//update the location
@ -66,7 +67,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
addHandler(on: attributedString)
}
public init(id: UUID = UUID(), action: PassthroughSubject<Void, Never> = PassthroughSubject<Void, Never>(), subscriber: AnyCancellable? = nil, surface: Surface, accessibleText: String? = nil, closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil) {
public init(id: UUID = UUID(), action: PassthroughSubject<Void, Never> = PassthroughSubject<Void, Never>(), subscriber: AnyCancellable? = nil, surface: Surface, accessibleText: String? = nil, closeButtonText: String = "Close", title: String? = nil, content: String? = nil, contentView: UIView? = nil, presenter: UIView? = nil) {
self.id = id
self.action = action
self.subscriber = subscriber
@ -76,6 +77,8 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
self.title = title
self.content = content
self.contentView = contentView
self.presenter = presenter
//create the tooltip click event
self.subscriber = action.sink { [weak self] in
guard let self else { return }
@ -83,7 +86,8 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
title: self.title,
content: self.content,
contentView: contentView,
closeButtonText: self.closeButtonText)
closeButtonText: self.closeButtonText,
presenter: self.presenter)
}
}

View File

@ -66,7 +66,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
public var textColorConfiguration: AnyColorable = ViewColorConfiguration().with {
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true)
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)
}.eraseToAnyColorable()
}.eraseToAnyColorable(){ didSet { setNeedsUpdate() }}
//--------------------------------------------------
// MARK: - Initializers
@ -156,7 +156,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
attributedText = mutableText
//get accessibility
updateAccessibilityLabel()
updateAccessibility()
//force a drawText
setNeedsDisplay()
@ -164,7 +164,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
}
}
open func updateAccessibilityLabel() {
open func updateAccessibility() {
accessibilityLabel = text
}
@ -222,6 +222,8 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
private var actions: [LabelAction] = [] {
didSet {
isUserInteractionEnabled = !actions.isEmpty
accessibilityTraits = !actions.isEmpty ? .link : .staticText
if actions.isEmpty {
tapGesture = nil
} else {
@ -264,7 +266,6 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
let actionText = accessibleText ?? NSString(string:text).substring(with: range)
let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:)))
accessibilityCustomActions?.append(accessibleAction)
return accessibleAction
}
@ -294,4 +295,3 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
return false
}
}

View File

@ -33,9 +33,10 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase<RadioBoxItem> {
public var selectorModels: [RadioBoxModel]? {
didSet {
if let selectorModels {
selectorViews = selectorModels.map { model in
selectorViews = selectorModels.enumerated().map { index, model in
return RadioBoxItem().with {
$0.accessibilityLabel = model.accessibileText
$0.accessibilityValue = "item \(index+1) of \(selectorModels.count)"
$0.text = model.text
$0.textAttributes = model.textAttributes
$0.subText = model.subText

View File

@ -243,24 +243,13 @@ open class RadioBoxItem: Control, Changeable {
//--------------------------------------------------
open override func updateView() {
updateLabels()
updateAccessibilityLabel()
updateAccessibility()
setNeedsLayout()
layoutIfNeeded()
}
open override func updateAccessibilityLabel() {
accessibilityValue = isSelected ? "1" : "0"
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.remove(.notEnabled)
}
open override func updateAccessibility() {
super.updateAccessibility()
if accessibilityLabel == nil {
setAccessibilityLabel(for: [textLabel, subTextLabel, subTextRightLabel])
}

View File

@ -33,13 +33,14 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase<RadioButtonItem> {
public var selectorModels: [RadioButtonModel]? {
didSet {
if let selectorModels {
selectorViews = selectorModels.map { model in
selectorViews = selectorModels.enumerated().map { index, model in
return RadioButtonItem().with {
$0.disabled = model.disabled
$0.surface = model.surface
$0.inputId = model.inputId
$0.value = model.value
$0.accessibilityLabel = model.accessibileText
$0.accessibilityValue = "item \(index+1) of \(selectorModels.count)"
$0.labelText = model.labelText
$0.labelTextAttributes = model.labelTextAttributes
$0.childText = model.childText

View File

@ -117,7 +117,7 @@ open class RadioSwatch: Control {
layer.setNeedsDisplay()
}
public override func updateAccessibilityLabel() {
public override func updateAccessibility() {
accessibilityLabel = text
}

View File

@ -12,7 +12,7 @@ import Combine
extension Tabs {
@objc(VDSTab)
open class Tab: View {
open class Tab: Control {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
@ -20,7 +20,7 @@ extension Tabs {
open var index: Int = 0
///label to write out the text
open var label: Label = Label()
open var label: Label = Label().with { $0.isUserInteractionEnabled = false }
///orientation of the tabs
open var orientation: Tabs.Orientation = .horizontal { didSet { setNeedsUpdate() } }
@ -33,16 +33,10 @@ extension Tabs {
///Sets the Position of the Selected/Hover Border Accent for All Tabs.
open var indicatorPosition: Tabs.IndicatorPosition = .bottom { didSet { setNeedsUpdate() } }
///An optional callback that is called when this Tab is clicked. Passes parameters (tabIndex).
open var onClick: ((Int) -> Void)? { didSet { setNeedsUpdate() } }
///If provided, it will set fixed width for this Tab.
open var width: CGFloat? { didSet { setNeedsUpdate() } }
///If provided, it will set this Tab to the Active Tab on render.
open var selected: Bool = false { didSet { setNeedsUpdate() } }
///The text label of the tab.
open var text: String = "" { didSet { setNeedsUpdate() } }
@ -71,7 +65,7 @@ extension Tabs {
//--------------------------------------------------
// MARK: - Configuration
//--------------------------------------------------
private var textColorConfiguration: SurfaceColorConfiguration { selected ? textColorSelectedConfiguration : textColorNonSelectedConfiguration }
private var textColorConfiguration: SurfaceColorConfiguration { isSelected ? textColorSelectedConfiguration : textColorNonSelectedConfiguration }
private var textColorNonSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight)
private var textColorSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
private var indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteRed, VDSColor.elementsPrimaryOndark)
@ -125,7 +119,8 @@ extension Tabs {
super.setup()
addSubview(label)
accessibilityTraits = .button
isAccessibilityElement = true
label.translatesAutoresizingMaskIntoConstraints = false
label.pinTrailing()
@ -149,23 +144,18 @@ extension Tabs {
layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor),
layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor),
layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
publisher(for: UITapGestureRecognizer())
.sink { [weak self] _ in
guard let self else { return }
self.onClick?(self.index)
}.store(in: &subscribers)
}
open override func updateView() {
super.updateView()
guard !text.isEmpty else { return }
//label properties
label.text = text
label.textStyle = textStyle
label.textPosition = textPosition
label.textColor = textColorConfiguration.getColor(self)
label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable()
//constaints
labelWidthConstraint?.isActive = false
@ -178,12 +168,17 @@ extension Tabs {
setNeedsLayout()
}
open override func updateAccessibility() {
super.updateAccessibility()
accessibilityLabel = text
}
open override func layoutSubviews() {
super.layoutSubviews()
removeBorders()
if selected {
if isSelected {
addBorder(side: indicatorSide, width: indicatorWidth, color: indicatorColorConfiguration.getColor(self))
}
}

View File

@ -211,20 +211,15 @@ open class Tabs: View {
let tabItem = Tab()
tabItem.size = size
tabItem.text = model.text
tabItem.onClick = model.onClick
tabItem.width = model.width
tabViews.append(tabItem)
tabStackView.addArrangedSubview(tabItem)
tabItem
.publisher(for: UITapGestureRecognizer())
.sink { [weak self] gesture in
guard let self, let tabItem = gesture.view as? Tab else { return }
if let selectedIndex = self.tabViews.firstIndex(of: tabItem) {
self.selectedIndex = selectedIndex
self.onTabChange?(selectedIndex)
}
}.store(in: &tabItem.subscribers)
tabItem.onClick = { [weak self] tab in
guard let self else { return }
model.onClick?(tab.index)
self.selectedIndex = tab.index
self.onTabChange?(tab.index)
}
}
setNeedsUpdate()
scrollToSelectedIndex(animated: false)
@ -249,14 +244,14 @@ open class Tabs: View {
// Update tab appearance based on properties
for (index, tabItem) in tabViews.enumerated() {
tabItem.size = size
tabItem.selected = selectedIndex == index
tabItem.isSelected = selectedIndex == index
tabItem.index = index
tabItem.minWidth = minWidth
tabItem.textPosition = textPosition
tabItem.orientation = orientation
tabItem.surface = surface
tabItem.indicatorPosition = indicatorPosition
tabItem.accessibilityLabel = "\(tabItem.text) \(tabItem.selected ? "selected" : "unselected") \(index+1) of \(tabViews.count)"
tabItem.accessibilityValue = "\(index+1) of \(tabViews.count) Tabs"
}
//update the width based on rules

View File

@ -295,7 +295,7 @@ open class EntryField: Control, Changeable {
}
if let tooltipTitle, let tooltipContent {
attributes.append(TooltipLabelAttribute(surface: surface, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView))
attributes.append(TooltipLabelAttribute(surface: surface, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView, presenter: self))
}
//set the titleLabel

View File

@ -198,10 +198,6 @@ open class InputField: EntryField, UITextFieldDelegate {
}
}
public override func updateAccessibilityLabel() {
}
open override func updateHelperLabel(){
//remove first
helperLabel.removeFromSuperview()

View File

@ -376,10 +376,10 @@ open class Tilelet: TileContainer {
updateIcons()
layoutIfNeeded()
updateAccessibilityLabel()
updateAccessibility()
}
open override func updateAccessibilityLabel() {
open override func updateAccessibility() {
setAccessibilityLabel(for: [badge.label, titleLockup.eyebrowLabel, titleLockup.titleLabel, titleLockup.subTitleLabel])
}
}

View File

@ -46,20 +46,57 @@ open class TitleLockup: View {
$0.distribution = .fill
}
///This logic applies when the type style and size used for the title and subtitle/eyebrow is exactly the same (not including the type weight). This should be automatically detected.
private var isUniformSize: Bool {
otherStandardStyle.value == titleModel?.standardStyle.value
}
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
// Sizes are from InVision design specs.
open var standardStyleConfiguration: StandardStyleConfigurationProvider = StandardStyleConfigurationProvider(styleConfigurations: [
.init(deviceType: .iPad,
titleStandardStyles: [.titleSmall, .titleMedium],
.init(deviceType: .iPad,
titleStandardStyles: [.bodySmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
.init(otherStandardStyles: [.bodySmall],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.bodyMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyMedium],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.bodyLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleSmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge, .titleSmall],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall, .bodyMedium, .bodyLarge],
topSpacing: VDSLayout.Spacing.space2X.value,
bottomSpacing: VDSLayout.Spacing.space2X.value)
]),
.init(deviceType: .iPad,
titleStandardStyles: [.titleLarge],
spacingConfigurations: [
@ -100,6 +137,30 @@ open class TitleLockup: View {
bottomSpacing: VDSLayout.Spacing.space6X.value),
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.bodySmall],
spacingConfigurations: [
.init(otherStandardStyles: [.bodySmall],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.bodyMedium],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyMedium],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.bodyLarge],
spacingConfigurations: [
.init(otherStandardStyles: [.bodyLarge],
topSpacing: VDSLayout.Spacing.space1X.value,
bottomSpacing: VDSLayout.Spacing.space1X.value)
]),
.init(deviceType: .iPhone,
titleStandardStyles: [.titleSmall],
spacingConfigurations: [
@ -152,6 +213,10 @@ open class TitleLockup: View {
bottomSpacing: VDSLayout.Spacing.space6X.value)
]),
])
private var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable()
private var textColorPrimaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark).eraseToAnyColorable()
//--------------------------------------------------
// MARK: - Public Properties
@ -182,6 +247,8 @@ open class TitleLockup: View {
open override func setup() {
super.setup()
titleLabel.textColorConfiguration = textColorPrimaryConfiguration
accessibilityElements = [eyebrowLabel, titleLabel, subTitleLabel]
addSubview(stackView)
@ -223,7 +290,7 @@ open class TitleLockup: View {
//--------------------------------------------------
open override func updateView() {
super.updateView()
let allLabelsTextPosition = textPosition.value
var eyebrowTextIsEmpty = true
var titleTextIsEmpty = true
@ -231,7 +298,7 @@ open class TitleLockup: View {
var topSpacing: CGFloat = 0.0
var bottomSpacing: CGFloat = 0.0
//get the spacing based on the title style and other style used for eyebrow and subtitle
if let titleModel,
let config = standardStyleConfiguration.spacing(for: titleModel.standardStyle, otherStandardStyle: otherStandardStyle) {
@ -242,15 +309,32 @@ open class TitleLockup: View {
if let eyebrowModel, !eyebrowModel.text.isEmpty {
eyebrowTextIsEmpty = false
eyebrowLabel.textPosition = allLabelsTextPosition
eyebrowLabel.textStyle = eyebrowModel.isBold ? otherStandardStyle.value.bold : otherStandardStyle.value.regular
eyebrowLabel.text = eyebrowModel.text
eyebrowLabel.attributes = eyebrowModel.textAttributes
eyebrowLabel.numberOfLines = eyebrowModel.numberOfLines
eyebrowLabel.surface = surface
//When uniform size is true
if let titleModel, isUniformSize {
if titleModel.isBold {
//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
}
} else {
eyebrowLabel.reset()
}
if let titleModel, !titleModel.text.isEmpty {
titleTextIsEmpty = false
titleLabel.textPosition = allLabelsTextPosition
@ -267,11 +351,11 @@ open class TitleLockup: View {
subTitleTextIsEmpty = false
subTitleLabel.textPosition = allLabelsTextPosition
subTitleLabel.textStyle = otherStandardStyle.value.regular
subTitleLabel.textColorConfiguration = subTitleModel.textColor == .secondary ? textColorSecondaryConfiguration : textColorPrimaryConfiguration
subTitleLabel.text = subTitleModel.text
subTitleLabel.attributes = subTitleModel.textAttributes
subTitleLabel.numberOfLines = subTitleModel.numberOfLines
subTitleLabel.surface = surface
subTitleLabel.disabled = subTitleModel.textColor == .secondary
} else {
subTitleLabel.reset()
}

View File

@ -23,6 +23,10 @@ extension TitleLockup {
case titleMedium
case titleSmall
case bodyLarge
case bodyMedium
case bodySmall
public var defaultValue: TextStyle.StandardStyle {.featureXSmall }
public var value: TextStyle.StandardStyle {

View File

@ -237,23 +237,16 @@ open class Toggle: Control, Changeable {
toggleView.surface = surface
toggleView.disabled = disabled
toggleView.isOn = isOn
updateAccessibilityLabel()
updateAccessibility()
}
open override func updateAccessibilityLabel() {
accessibilityValue = isSelected ? "1" : "0"
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
open override func updateAccessibility() {
super.updateAccessibility()
if showText {
setAccessibilityLabel(for: [label])
} else {
accessibilityLabel = "Toggle"
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled{
accessibilityTraits.remove(.notEnabled)
}
setAccessibilityLabel(for: [label])
}
open override var intrinsicContentSize: CGSize {

View File

@ -199,23 +199,12 @@ open class ToggleView: Control, Changeable {
//--------------------------------------------------
open override func updateView() {
updateToggle()
updateAccessibilityLabel()
updateAccessibility()
}
open override func updateAccessibilityLabel() {
open override func updateAccessibility() {
super.updateAccessibility()
accessibilityLabel = "Toggle"
accessibilityValue = isSelected ? "1" : "0"
if !accessibilityTraits.contains(.selected) && isSelected {
accessibilityTraits.insert(.selected)
} else if accessibilityTraits.contains(.selected) && !isSelected{
accessibilityTraits.remove(.selected)
}
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled{
accessibilityTraits.remove(.notEnabled)
}
}
}

View File

@ -135,7 +135,8 @@ open class Tooltip: Control, TooltipLaunchable {
title: tooltip.title,
content: tooltip.content,
contentView: tooltip.contentView,
closeButtonText: tooltip.closeButtonText)
closeButtonText: tooltip.closeButtonText,
presenter: self)
})
}
@ -166,20 +167,33 @@ open class Tooltip: Control, TooltipLaunchable {
imageView.image = infoImage.withTintColor(imageColor)
}
open override func updateAccessibilityLabel() {
if !accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.insert(.notEnabled)
} else if accessibilityTraits.contains(.notEnabled) && !isEnabled {
accessibilityTraits.remove(.notEnabled)
}
open override func updateAccessibility() {
super.updateAccessibility()
var label = title
if label == nil {
label = content
}
accessibilityHint = isEnabled ? "Click to open Tooltip." : ""
accessibilityValue = "collapsed"
if let label {
accessibilityLabel = "Tooltip: \(label)"
accessibilityLabel = label
}
}
public static func accessibleText(for title: String?, content: String?, closeButtonText: String) -> String {
var label = ""
if let title {
label = title
}
if let content {
if !label.isEmpty {
label += ","
}
label += content
}
return label
}
}

View File

@ -36,7 +36,7 @@ open class TooltipAlertViewController: UIViewController, Surfaceable {
open var contentText: String? { didSet { updateView() }}
open var contentView: UIView? { didSet { updateView() }}
open var closeButtonText: String = "Close" { didSet { updateView() }}
open var presenter: UIView? { didSet { updateView() }}
//--------------------------------------------------
// MARK: - Configuration
//--------------------------------------------------
@ -50,28 +50,41 @@ open class TooltipAlertViewController: UIViewController, Surfaceable {
isModalInPresentation = true
setup()
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIAccessibility.post(notification: .screenChanged, argument: tooltipDialog)
}
private func dismiss() {
dismiss(animated: true) { [weak self] in
guard let self, let presenter else { return }
UIAccessibility.post(notification: .layoutChanged, argument: presenter)
}
}
open func setup() {
view.accessibilityElements = [tooltipDialog]
//left-right swipe
view.publisher(for: UISwipeGestureRecognizer().with{ $0.direction = .right })
.sink { [weak self] swipe in
guard let self else { return }
self.dismiss(animated: true, completion: nil)
}.store(in: &subscribers)
guard let self else { return }
self.dismiss()
}.store(in: &subscribers)
//tapping in background
view.publisher(for: UITapGestureRecognizer().with{ $0.numberOfTapsRequired = 1 })
.sink { [weak self] swipe in
guard let self else { return }
self.dismiss(animated: true, completion: nil)
}.store(in: &subscribers)
guard let self else { return }
self.dismiss()
}.store(in: &subscribers)
//clicking button
onClickSubscriber = tooltipDialog.closeButton.publisher(for: .touchUpInside)
.sink {[weak self] button in
guard let self else { return }
self.dismiss(animated: true, completion: nil)
}
guard let self else { return }
self.dismiss()
}
view.addSubview(tooltipDialog)
@ -160,9 +173,8 @@ open class TooltipDialog: View, UIScrollViewDelegate {
//--------------------------------------------------
open override func setup() {
super.setup()
layer.cornerRadius = 8
contentStackView.isAccessibilityElement = true
contentStackView.addArrangedSubview(titleLabel)
contentStackView.addArrangedSubview(contentLabel)
scrollView.addSubview(contentStackView)
@ -204,7 +216,7 @@ open class TooltipDialog: View, UIScrollViewDelegate {
open override func updateView() {
super.updateView()
backgroundColor = backgroundColorConfiguration.getColor(self)
scrollView.indicatorStyle = surface == .light ? .black : .white
@ -257,6 +269,7 @@ open class TooltipDialog: View, UIScrollViewDelegate {
closeButton.setTitleColor(closeButtonTextColor, for: .normal)
closeButton.setTitleColor(closeButtonTextColor, for: .highlighted)
closeButton.setTitle(closeButtonText, for: .normal)
closeButton.accessibilityLabel = closeButtonText
contentStackView.setNeedsLayout()
contentStackView.layoutIfNeeded()
@ -282,7 +295,19 @@ open class TooltipDialog: View, UIScrollViewDelegate {
//stackView between the bottom of the scrollView
contentStackViewBottomConstraint?.constant = -containerViewInset
}
heightConstraint?.constant = contentHeight
}
open override func updateAccessibility() {
var label = Tooltip.accessibleText(for: titleText, content: contentText, closeButtonText: closeButtonText)
if !label.isEmpty {
label += ","
}
contentStackView.accessibilityLabel = label
contentStackView.accessibilityHint = "Click on the \(closeButtonText) button to close."
contentStackView.accessibilityValue = "expanded"
accessibilityElements = [contentStackView, closeButton]
}
}

View File

@ -9,11 +9,11 @@ import Foundation
import UIKit
public protocol TooltipLaunchable {
func presentTooltip(surface: Surface, title: String?, content: String?, contentView: UIView?, closeButtonText: String)
func presentTooltip(surface: Surface, title: String?, content: String?, contentView: UIView?, closeButtonText: String, presenter: UIView?)
}
extension TooltipLaunchable {
public func presentTooltip(surface: Surface, title: String?, content: String?, contentView: UIView? = nil, closeButtonText: String = "Close") {
public func presentTooltip(surface: Surface, title: String?, content: String?, contentView: UIView? = nil, closeButtonText: String = "Close", presenter: UIView? = nil) {
if let presenting = UIApplication.topViewController() {
let tooltipViewController = TooltipAlertViewController(nibName: nil, bundle: nil).with {
$0.surface = surface
@ -21,6 +21,7 @@ extension TooltipLaunchable {
$0.contentText = content
$0.contentView = contentView
$0.closeButtonText = closeButtonText
$0.presenter = presenter
$0.modalPresentationStyle = .overCurrentContext
$0.modalTransitionStyle = .crossDissolve
}

View File

@ -57,7 +57,8 @@ open class TrailingTooltipLabel: View, TooltipLaunchable {
self.presentTooltip(surface: self.surface,
title: self.tooltipTitle,
content: self.tooltipContent,
closeButtonText: self.tooltipCloseButtonText)
closeButtonText: self.tooltipCloseButtonText,
presenter: self)
}.store(in: &subscribers)
}
@ -126,7 +127,8 @@ extension Label {
closeButtonText: model.closeButtonText,
title: model.title,
content: model.content,
contentView: model.contentView)
contentView: model.contentView,
presenter: self)
newAttributes.append(tooltip)
}

View File

@ -12,7 +12,7 @@ public protocol ViewProtocol {
// Can setup ui here. Should be called in the initialization functions.
func setup()
func updateAccessibilityLabel()
func updateAccessibility()
}
extension ViewProtocol where Self: UIView {

View File

@ -1,3 +1,12 @@
1.0.35
=======
- ONEAPP-4684 - (Acessibility) Tooltip
- ONEAPP-4681 - (Acessibility) Checkbox
- ONEAPP-4825 - (Acessibility) Radiobutton
- ONEAPP-5104 - (Acessibility) Button
- ONEAPP-4115 - (Acessibility) Tabs
- TitleLockup update for Janet release
1.0.34
=======
- Added new spec for Bottom Inset for TextStyle