diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 5dc81d47..95e8e27f 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 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 */; }; 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 +135,7 @@ EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; EA1F266128B945070033E859 /* RadioSwatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = ""; }; EA1F266228B945070033E859 /* RadioSwatchGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSwatchGroup.swift; sourceTree = ""; }; + EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = ""; }; 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 = ""; }; EA336170288B19200071C351 /* VDS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = VDS.docc; sourceTree = ""; }; @@ -661,6 +663,7 @@ EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */, EAF7F0AC289B142900B287F5 /* StrikeThroughLabelAttribute.swift */, EAF7F0AE289B144C00B287F5 /* UnderlineLabelAttribute.swift */, + EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */, ); path = Attributes; sourceTree = ""; @@ -821,6 +824,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 */, diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift new file mode 100644 index 00000000..e6047dd0 --- /dev/null +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -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() + 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 = PassthroughSubject(), 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 + } +} +