Merge branch 'update/tooltip' into 'develop'
added tooltiplabelattribute See merge request BPHV_MIPS/vds_ios!59
This commit is contained in:
commit
8e93c84060
@ -15,6 +15,8 @@
|
||||
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; };
|
||||
EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1F266128B945070033E859 /* RadioSwatch.swift */; };
|
||||
EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1F266228B945070033E859 /* RadioSwatchGroup.swift */; };
|
||||
EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; };
|
||||
EA297A5729FB0A360031ED56 /* AppleGuidlinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidlinesTouchable.swift */; };
|
||||
EA336171288B19200071C351 /* VDS.docc in Sources */ = {isa = PBXBuildFile; fileRef = EA336170288B19200071C351 /* VDS.docc */; };
|
||||
EA336177288B19210071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33616C288B19200071C351 /* VDS.framework */; };
|
||||
EA33617C288B19210071C351 /* VDSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33617B288B19210071C351 /* VDSTests.swift */; };
|
||||
@ -134,6 +136,8 @@
|
||||
EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
|
||||
EA1F266128B945070033E859 /* RadioSwatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = "<group>"; };
|
||||
EA1F266228B945070033E859 /* RadioSwatchGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatchGroup.swift; sourceTree = "<group>"; };
|
||||
EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = "<group>"; };
|
||||
EA297A5629FB0A360031ED56 /* AppleGuidlinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidlinesTouchable.swift; sourceTree = "<group>"; };
|
||||
EA33616C288B19200071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EA33616F288B19200071C351 /* VDS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VDS.h; sourceTree = "<group>"; };
|
||||
EA336170288B19200071C351 /* VDS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = VDS.docc; sourceTree = "<group>"; };
|
||||
@ -421,6 +425,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */,
|
||||
EA297A5629FB0A360031ED56 /* AppleGuidlinesTouchable.swift */,
|
||||
EAF1FE9A29DB1A6000101452 /* Changeable.swift */,
|
||||
EAF1FE9829D4850E00101452 /* Clickable.swift */,
|
||||
EAA5EEDF28F49DB3003B3210 /* Colorable.swift */,
|
||||
@ -661,6 +666,7 @@
|
||||
EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */,
|
||||
EAF7F0AC289B142900B287F5 /* StrikeThroughLabelAttribute.swift */,
|
||||
EAF7F0AE289B144C00B287F5 /* UnderlineLabelAttribute.swift */,
|
||||
EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */,
|
||||
);
|
||||
path = Attributes;
|
||||
sourceTree = "<group>";
|
||||
@ -794,6 +800,7 @@
|
||||
EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */,
|
||||
EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */,
|
||||
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */,
|
||||
EA297A5729FB0A360031ED56 /* AppleGuidlinesTouchable.swift in Sources */,
|
||||
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
|
||||
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */,
|
||||
EA89201328B568D8006B9984 /* RadioBox.swift in Sources */,
|
||||
@ -821,6 +828,7 @@
|
||||
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */,
|
||||
EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */,
|
||||
EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */,
|
||||
EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */,
|
||||
EA985BEA29689B6D00F2FF2E /* TileletSubTitleModel.swift in Sources */,
|
||||
EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */,
|
||||
EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */,
|
||||
|
||||
97
VDS/Components/Label/Attributes/TooltipLabelAttribute.swift
Normal file
97
VDS/Components/Label/Attributes/TooltipLabelAttribute.swift
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// TooltipLabelAttribute.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 4/27/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDSColorTokens
|
||||
|
||||
public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable {
|
||||
public var id = UUID()
|
||||
public var action = PassthroughSubject<Void, Never>()
|
||||
private var subscriber: AnyCancellable?
|
||||
public var location: Int = 0
|
||||
public var length: Int = 3
|
||||
public var surface: Surface = .light
|
||||
public var accessibleText: String? = "Tool Tip"
|
||||
public var closeButtonText: String = "Close"
|
||||
public var size: Tooltip.Size = .medium
|
||||
public var title: String
|
||||
public var content: String
|
||||
|
||||
public func setAttribute(on attributedString: NSMutableAttributedString) {
|
||||
//update the location
|
||||
location = attributedString.string.count
|
||||
|
||||
var imageTintColor: UIColor = surface == .light ? VDSColor.elementsPrimaryOnlight : VDSColor.elementsPrimaryOndark
|
||||
|
||||
//see if you can get the current textColor
|
||||
var originalRange = NSMakeRange(0, attributedString.length)
|
||||
if let textColor = attributedString.attribute(.foregroundColor, at: 0, effectiveRange: &originalRange) as? UIColor {
|
||||
imageTintColor = textColor
|
||||
}
|
||||
|
||||
//create the space in the attirbuted String for the tooltip image and click action
|
||||
let spaceForTooltip = String(repeating: " ", count: length)
|
||||
|
||||
//find the middle of the space
|
||||
let middle = (length/2)
|
||||
|
||||
//add the space to the attributed string
|
||||
attributedString.insert(NSAttributedString(string: spaceForTooltip), at: location)
|
||||
|
||||
//create the frame in which to hold the icon
|
||||
let frame = CGRect(x: 0, y: 0, width: size.dimensions.width, height: size.dimensions.width)
|
||||
|
||||
//create the image icon and match the color of the text
|
||||
let tooltipAttribute = ImageLabelAttribute(location: location + middle,
|
||||
length: 1,
|
||||
imageName: "info",
|
||||
frame: frame,
|
||||
tintColor: imageTintColor)
|
||||
|
||||
//create the action for the tooltip click
|
||||
let tooltipAction = ActionLabelAttribute(location: location - middle,
|
||||
length: length + middle,
|
||||
shouldUnderline: false,
|
||||
action: action)
|
||||
|
||||
//apply the attribtes to the current attributedString
|
||||
tooltipAttribute.setAttribute(on: attributedString)
|
||||
tooltipAction.setAttribute(on: attributedString)
|
||||
}
|
||||
|
||||
public init(id: UUID = UUID(), action: PassthroughSubject<Void, Never> = PassthroughSubject<Void, Never>(), subscriber: AnyCancellable? = nil, surface: Surface, accessibleText: String? = nil, closeButtonText: String, size: Tooltip.Size, title: String, content: String) {
|
||||
self.id = id
|
||||
self.action = action
|
||||
self.subscriber = subscriber
|
||||
self.surface = surface
|
||||
self.accessibleText = accessibleText
|
||||
self.closeButtonText = closeButtonText
|
||||
self.size = size
|
||||
self.title = title
|
||||
self.content = content
|
||||
|
||||
//create the tooltip click event
|
||||
self.subscriber = action.sink { [weak self] in
|
||||
guard let self else { return }
|
||||
self.presentTooltip(surface: self.surface,
|
||||
title: self.title,
|
||||
content: self.content,
|
||||
closeButtonText: self.closeButtonText)
|
||||
}
|
||||
}
|
||||
|
||||
public static func == (lhs: TooltipLabelAttribute, rhs: TooltipLabelAttribute) -> Bool {
|
||||
lhs.isEqual(rhs)
|
||||
}
|
||||
|
||||
public func isEqual(_ equatable: TooltipLabelAttribute) -> Bool {
|
||||
return id == equatable.id && range == equatable.range
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,11 +156,11 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
||||
|
||||
//add attribute on the string
|
||||
attribute.setAttribute(on: mutableAttributedString)
|
||||
|
||||
|
||||
//see if the attribute is Actionable
|
||||
if let actionable = attribute as? any ActionLabelAttributeModel{
|
||||
//create a accessibleAction
|
||||
let customAccessibilityAction = customAccessibilityAction(range: actionable.range, accessibleText: actionable.accessibleText)
|
||||
let customAccessibilityAction = customAccessibilityAction(text: mutableAttributedString.string, range: actionable.range, accessibleText: actionable.accessibleText)
|
||||
|
||||
//create a wrapper for the attributes range, block and
|
||||
actions.append(LabelAction(range: actionable.range, action: actionable.action, accessibilityID: customAccessibilityAction?.hashValue ?? -1))
|
||||
@ -263,7 +263,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessibility For Actions
|
||||
//--------------------------------------------------
|
||||
private func customAccessibilityAction(range: NSRange, accessibleText: String? = nil) -> UIAccessibilityCustomAction? {
|
||||
private func customAccessibilityAction(text: String?, range: NSRange, accessibleText: String? = nil) -> UIAccessibilityCustomAction? {
|
||||
|
||||
guard let text = text else { return nil }
|
||||
//TODO: accessibilityHint for Label
|
||||
|
||||
@ -172,3 +172,12 @@ open class Tooltip: Control, TooltipLaunchable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: AppleGuidlinesTouchable
|
||||
extension Tooltip: AppleGuidlinesTouchable {
|
||||
|
||||
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -64,31 +64,67 @@ open class TrailingTooltipLabel: View, TooltipLaunchable {
|
||||
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
var attributes: [any LabelAttributeModel] = []
|
||||
if let labelAttributes {
|
||||
attributes.append(contentsOf: labelAttributes)
|
||||
}
|
||||
|
||||
var updatedLabelText = labelText
|
||||
|
||||
//add the tool tip
|
||||
if let oldText = updatedLabelText, !tooltipTitle.isEmpty, !tooltipContent.isEmpty {
|
||||
let tooltipUpdateText = "\(oldText) " //create a little space between the final character and tooltip image
|
||||
let frame = CGRect(x: 0, y: tooltipYOffset, width: tooltipSize.dimensions.width, height: tooltipSize.dimensions.width)
|
||||
let color = textColorConfiguration.getColor(self)
|
||||
let tooltipAttribute = ImageLabelAttribute(location: tooltipUpdateText.count - 2, imageName: "info", frame: frame, tintColor: color)
|
||||
let tooltipAction = ActionLabelAttribute(location: tooltipUpdateText.count - 3, length: 3, shouldUnderline: false, action: tooltipAction)
|
||||
updatedLabelText = tooltipUpdateText
|
||||
attributes.append(tooltipAttribute)
|
||||
attributes.append(tooltipAction)
|
||||
}
|
||||
//set the titleLabel
|
||||
label.text = updatedLabelText
|
||||
label.attributes = attributes
|
||||
|
||||
label.text = labelText
|
||||
label.textStyle = labelTextStyle
|
||||
label.textPosition = labelTextPosition
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
|
||||
//add tooltip
|
||||
if let labelText, !labelText.isEmpty, !tooltipTitle.isEmpty, !tooltipContent.isEmpty {
|
||||
//create the model
|
||||
let model = Label.TooltipModel(surface: surface,
|
||||
closeButtonText: tooltipCloseButtonText,
|
||||
size: tooltipSize,
|
||||
title: tooltipTitle,
|
||||
content: tooltipContent)
|
||||
|
||||
//add the model
|
||||
label.addTooltip(model: model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Label {
|
||||
public struct TooltipModel {
|
||||
public var surface: Surface
|
||||
public var closeButtonText: String
|
||||
public var size: Tooltip.Size
|
||||
public var title: String
|
||||
public var content: String
|
||||
|
||||
public init(surface: Surface = .light, closeButtonText: String = "Close", size: Tooltip.Size = .medium, title: String, content: String) {
|
||||
self.surface = surface
|
||||
self.closeButtonText = closeButtonText
|
||||
self.size = size
|
||||
self.title = title
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
public func addTooltip(model: TooltipModel) {
|
||||
|
||||
var newAttributes: [any LabelAttributeModel] = []
|
||||
if let attributes {
|
||||
attributes.forEach { attribute in
|
||||
if type(of: attribute) != TooltipLabelAttribute.self {
|
||||
newAttributes.append(attribute)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let text = text, !text.isEmpty {
|
||||
let tooltip = TooltipLabelAttribute(surface: surface,
|
||||
closeButtonText: model.closeButtonText,
|
||||
size: model.size,
|
||||
title: model.title,
|
||||
content: model.content)
|
||||
newAttributes.append(tooltip)
|
||||
}
|
||||
|
||||
if !newAttributes.isEmpty {
|
||||
attributes = newAttributes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
VDS/Protocols/AppleGuidlinesTouchable.swift
Normal file
31
VDS/Protocols/AppleGuidlinesTouchable.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// AppleGuidlinesTouchable.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 4/27/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol AppleGuidlinesTouchable {
|
||||
static var minimumTappableArea: CGFloat { get }
|
||||
static func acceptablyOutsideBounds(point: CGPoint, bounds: CGRect) -> Bool
|
||||
}
|
||||
|
||||
extension AppleGuidlinesTouchable {
|
||||
|
||||
static public var minimumTappableArea: CGFloat {
|
||||
return 45.0
|
||||
}
|
||||
|
||||
// If the control is smaller than 45pt by width or height, this will compensate.
|
||||
static public func acceptablyOutsideBounds(point: CGPoint, bounds: CGRect) -> Bool {
|
||||
|
||||
let faultToleranceX: CGFloat = max((minimumTappableArea - bounds.size.width) / 2.0, 0)
|
||||
let faultToleranceY: CGFloat = max((minimumTappableArea - bounds.size.height) / 2.0, 0)
|
||||
let area = bounds.insetBy(dx: -faultToleranceX, dy: -faultToleranceY)
|
||||
|
||||
let contains = area.contains(point)
|
||||
return contains
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user