Compare commits

...

6 Commits

Author SHA1 Message Date
Matt Bruce
13c1265928 Merge branch 'release/11_4_0' into refactor/button-style 2024-03-13 13:48:47 -05:00
Matt Bruce
bd50e75f85 added TextField
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-03-13 13:40:37 -05:00
Matt Bruce
413d5567af fixed bug for the Label
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-03-13 10:50:56 -05:00
Matt Bruce
10fdd6bcb8 updated TextView to mimic label/buttonbase
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-03-13 09:09:45 -05:00
Matt Bruce
3c375bea39 update method to set text
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-03-13 08:59:39 -05:00
Matt Bruce
b258608b77 match pattern of the label
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-03-13 08:56:08 -05:00
5 changed files with 444 additions and 56 deletions

View File

@ -132,6 +132,7 @@
EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD068912A560B65002E3A2D /* LoaderViewController.swift */; }; EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD068912A560B65002E3A2D /* LoaderViewController.swift */; };
EAD068942A560C13002E3A2D /* LoaderLaunchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD068932A560C13002E3A2D /* LoaderLaunchable.swift */; }; EAD068942A560C13002E3A2D /* LoaderLaunchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD068932A560C13002E3A2D /* LoaderLaunchable.swift */; };
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; }; EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; };
EAE785352BA22825009428EA /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE785342BA22825009428EA /* TextField.swift */; };
EAEEEC922B1F807300531FC2 /* BadgeChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC912B1F807300531FC2 /* BadgeChangeLog.txt */; }; EAEEEC922B1F807300531FC2 /* BadgeChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC912B1F807300531FC2 /* BadgeChangeLog.txt */; };
EAEEEC962B1F893B00531FC2 /* ButtonChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC952B1F893B00531FC2 /* ButtonChangeLog.txt */; }; EAEEEC962B1F893B00531FC2 /* ButtonChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC952B1F893B00531FC2 /* ButtonChangeLog.txt */; };
EAEEEC982B1F8DD100531FC2 /* LineChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC972B1F8DD100531FC2 /* LineChangeLog.txt */; }; EAEEEC982B1F8DD100531FC2 /* LineChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEEC972B1F8DD100531FC2 /* LineChangeLog.txt */; };
@ -303,6 +304,7 @@
EAD068912A560B65002E3A2D /* LoaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderViewController.swift; sourceTree = "<group>"; }; EAD068912A560B65002E3A2D /* LoaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderViewController.swift; sourceTree = "<group>"; };
EAD068932A560C13002E3A2D /* LoaderLaunchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderLaunchable.swift; sourceTree = "<group>"; }; EAD068932A560C13002E3A2D /* LoaderLaunchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderLaunchable.swift; sourceTree = "<group>"; };
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; }; EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
EAE785342BA22825009428EA /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
EAEEEC912B1F807300531FC2 /* BadgeChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BadgeChangeLog.txt; sourceTree = "<group>"; }; EAEEEC912B1F807300531FC2 /* BadgeChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BadgeChangeLog.txt; sourceTree = "<group>"; };
EAEEEC952B1F893B00531FC2 /* ButtonChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonChangeLog.txt; sourceTree = "<group>"; }; EAEEEC952B1F893B00531FC2 /* ButtonChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonChangeLog.txt; sourceTree = "<group>"; };
EAEEEC972B1F8DD100531FC2 /* LineChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LineChangeLog.txt; sourceTree = "<group>"; }; EAEEEC972B1F8DD100531FC2 /* LineChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LineChangeLog.txt; sourceTree = "<group>"; };
@ -800,6 +802,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EAC925872911C9DE00091998 /* InputField.swift */, EAC925872911C9DE00091998 /* InputField.swift */,
EAE785342BA22825009428EA /* TextField.swift */,
); );
path = InputField; path = InputField;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1053,6 +1056,7 @@
EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */, EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */,
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
EAE785352BA22825009428EA /* TextField.swift in Sources */,
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */, EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */,

View File

@ -61,7 +61,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
open var surface: Surface = .light { didSet { setNeedsUpdate() } } open var surface: Surface = .light { didSet { setNeedsUpdate() } }
/// Text that will be used in the titleLabel. /// Text that will be used in the titleLabel.
open var text: String? { didSet { setNeedsUpdate() } } open var text: String? { didSet { textSetMode = .text; setNeedsUpdate() } }
/// Array of LabelAttributeModel objects used in rendering the text. /// Array of LabelAttributeModel objects used in rendering the text.
open var textAttributes: [any LabelAttributeModel]? { nil } open var textAttributes: [any LabelAttributeModel]? { nil }
@ -121,7 +121,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
} }
open func updateView() { open func updateView() {
updateLabel() restyleText()
} }
open func updateAccessibility() { open func updateAccessibility() {
@ -152,36 +152,115 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
return CGSize(width: adjustedWidth, height: adjustedHeight) return CGSize(width: adjustedWidth, height: adjustedHeight)
} }
private enum TextSetMode {
case text
case attributedText
}
private var textSetMode: TextSetMode = .text
/// :nodoc:
override public func setTitle(_ title: String?, for state: UIControl.State) {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
text = title
}
/// :nodoc:
override public func setAttributedTitle(_ title: NSAttributedString?, for state: UIControl.State) {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
textSetMode = .attributedText
styleAttributedText(title, for: state)
}
/// Gets or sets the text alignment of the button's title label.
/// Default value = `.natural`
public var textAlignment: NSTextAlignment = .natural {
didSet {
if textAlignment != oldValue {
// Text alignment can be part of our paragraph style, so we may need to
// re-style when changed
restyleText()
}
}
}
/// Gets or sets the line break mode of the button's title label.
/// Default value = `.byTruncatingTail`
public var lineBreakMode: NSLineBreakMode = .byTruncatingTail {
didSet {
if lineBreakMode != oldValue {
// Line break mode can be part of our paragraph style, so we may need to
// re-style when changed
restyleText()
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Methods // MARK: - Private Methods
//-------------------------------------------------- //--------------------------------------------------
private func updateLabel() {
private func restyleText() {
//clear the arrays holding actions if textSetMode == .text {
accessibilityCustomActions = [] styleText(text, for: state)
if let text, !text.isEmpty {
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: text,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColor,
alignment: titleLabel?.textAlignment ?? .center,
lineBreakMode: titleLabel?.lineBreakMode ?? .byTruncatingTail)
//apply any attributes
if let attributes = textAttributes {
mutableText.apply(attributes: attributes)
}
//set the attributed text
setAttributedTitle(mutableText, for: .normal)
setAttributedTitle(mutableText, for: .highlighted)
} else { } else {
setAttributedTitle(nil, for: .normal) styleAttributedText(currentAttributedTitle, for: state)
setAttributedTitle(nil, for: .highlighted)
titleLabel?.text = nil
} }
} }
private func styleText(_ newValue: String!, for state: UIControl.State) {
defer { invalidateIntrinsicContentSize() }
guard let newValue else {
// We don't need to use attributed text
super.setAttributedTitle(nil, for: state)
super.setTitle(newValue, for: state)
return
}
accessibilityCustomActions = []
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: newValue,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColor,
alignment: titleLabel?.textAlignment ?? .center,
lineBreakMode: titleLabel?.lineBreakMode ?? .byTruncatingTail)
//apply any attributes
if let attributes = textAttributes {
mutableText.apply(attributes: attributes)
}
// Set attributed text to match typography
super.setAttributedTitle(mutableText, for: state)
}
private func styleAttributedText(_ newValue: NSAttributedString?, for state: UIControl.State) {
defer { invalidateIntrinsicContentSize() }
guard let newValue = newValue else {
// We don't need any additional styling
super.setAttributedTitle(newValue, for: state)
return
}
//clear the arrays holding actions
accessibilityCustomActions = []
let mutableText = NSMutableAttributedString(attributedString: newValue)
//apply any attributes
if let attributes = textAttributes {
mutableText.apply(attributes: attributes)
}
// Modify attributed text to match typography
super.setAttributedTitle(mutableText, for: state)
}
} }

View File

@ -64,10 +64,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate {
} }
/// UITextField shown in the InputField. /// UITextField shown in the InputField.
open var textField = UITextField().with { open var textField = TextField()
$0.translatesAutoresizingMaskIntoConstraints = false
$0.font = TextStyle.bodyLarge.font
}
/// Color configuration for the textField. /// Color configuration for the textField.
open var textFieldTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { open var textFieldTextColorConfiguration: AnyColorable = ViewColorConfiguration().with {

View File

@ -0,0 +1,253 @@
//
// TextField.swift
// VDS
//
// Created by Matt Bruce on 3/13/24.
//
import Foundation
import UIKit
import Combine
import VDSColorTokens
@objc(VDSTextField)
open class TextField: UITextField, ViewProtocol {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init() {
super.init(frame: .zero)
initialSetup()
}
public override init(frame: CGRect) {
super.init(frame: frame)
initialSetup()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
initialSetup()
}
//--------------------------------------------------
// MARK: - Combine Properties
//--------------------------------------------------
/// Set of Subscribers for any Publishers for this Control.
open var subscribers = Set<AnyCancellable>()
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private var initialSetupPerformed = false
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
/// Key of whether or not updateView() is called in setNeedsUpdate()
open var shouldUpdateView: Bool = true
open var surface: Surface = .light { didSet { setNeedsUpdate() } }
/// Array of LabelAttributeModel objects used in rendering the text.
open var textAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() } }
/// TextStyle used on the titleLabel.
open var textStyle: TextStyle { .defaultStyle }
/// Will determine if a scaled font should be used for the titleLabel font.
open var useScaledFont: Bool = false { didSet { setNeedsUpdate() } }
open override var isEnabled: Bool { didSet { setNeedsUpdate() } }
open override var isSelected: Bool { didSet { setNeedsUpdate() } }
/// State of animating isHighlight.
public var isHighlighting = false
/// Whether the Control should handle the isHighlighted state.
open var shouldHighlight: Bool { isHighlighting == false }
/// Whether the Control is highlighted or not.
open override var isHighlighted: Bool {
didSet {
if shouldHighlight {
isHighlighting = true
setNeedsUpdate()
isHighlighting = false
}
}
}
open var textColorConfiguration: AnyColorable = ViewColorConfiguration().with {
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true)
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)
}.eraseToAnyColorable(){ didSet { setNeedsUpdate() }}
open override var textColor: UIColor? {
get { textColorConfiguration.getColor(self) }
set { }
}
private enum TextSetMode {
case text
case attributedText
}
private var textSetMode: TextSetMode = .text
/// :nodoc:
open override var text: String! {
get { super.text }
set {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
textSetMode = .text
styleText(newValue)
}
}
/// :nodoc:
open override var attributedText: NSAttributedString? {
get { super.attributedText }
set {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
textSetMode = .attributedText
styleAttributedText(newValue)
}
}
/// :nodoc:
open override var textAlignment: NSTextAlignment {
didSet {
if textAlignment != oldValue {
// Text alignment can be part of our paragraph style, so we may need to
// re-style when changed
restyleText()
}
}
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open func initialSetup() {
if !initialSetupPerformed {
initialSetupPerformed = true
backgroundColor = .clear
translatesAutoresizingMaskIntoConstraints = false
accessibilityCustomActions = []
setup()
setNeedsUpdate()
}
}
open func setup() {
translatesAutoresizingMaskIntoConstraints = false
}
open func updateView() {
restyleText()
}
open func updateAccessibility() {}
open func reset() {
shouldUpdateView = false
surface = .light
text = nil
accessibilityCustomActions = []
shouldUpdateView = true
setNeedsUpdate()
}
//--------------------------------------------------
// MARK: - Overrides Methods
//--------------------------------------------------
/// :nodoc
open override func textRect(forBounds bounds: CGRect) -> CGRect {
super.textRect(forBounds: bounds).inset(by: textStyle.edgeInsets)
}
/// :nodoc
open override func editingRect(forBounds bounds: CGRect) -> CGRect {
super.editingRect(forBounds: bounds).inset(by: textStyle.edgeInsets)
}
/// :nodoc
open override func clearButtonRect(forBounds bounds: CGRect) -> CGRect {
super.clearButtonRect(forBounds: bounds).offsetBy(dx: -textStyle.edgeInsets.right, dy: 0)
}
/// :nodoc
open override func leftViewRect(forBounds bounds: CGRect) -> CGRect {
super.leftViewRect(forBounds: bounds).offsetBy(dx: textStyle.edgeInsets.left, dy: 0)
}
/// :nodoc
open override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
super.rightViewRect(forBounds: bounds).offsetBy(dx: -textStyle.edgeInsets.right, dy: 0)
}
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
private func restyleText() {
if textSetMode == .text {
styleText(text)
} else {
styleAttributedText(attributedText)
}
}
private func styleText(_ newValue: String!) {
defer { invalidateIntrinsicContentSize() }
guard let newValue else {
// We don't need to use attributed text
super.attributedText = nil
super.text = newValue
return
}
accessibilityCustomActions = []
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: newValue,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColorConfiguration.getColor(self),
alignment: textAlignment,
lineBreakMode: .byWordWrapping)
applyAttributes(mutableText)
// Set attributed text to match typography
super.attributedText = mutableText
}
private func styleAttributedText(_ newValue: NSAttributedString?) {
defer { invalidateIntrinsicContentSize() }
guard let newValue = newValue else {
// We don't need any additional styling
super.attributedText = newValue
return
}
let mutableText = NSMutableAttributedString(attributedString: newValue)
applyAttributes(mutableText)
// Modify attributed text to match typography
super.attributedText = mutableText
}
private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) {
if let textAttributes {
mutableAttributedString.apply(attributes: textAttributes)
}
}
}

View File

@ -70,21 +70,43 @@ open class TextView: UITextView, ViewProtocol {
get { textColorConfiguration.getColor(self) } get { textColorConfiguration.getColor(self) }
set { } set { }
} }
override public var text: String! { private enum TextSetMode {
case text
case attributedText
}
private var textSetMode: TextSetMode = .text
/// :nodoc:
open override var text: String! {
get { super.text } get { super.text }
set { set {
super.text = newValue // When text is set, we may need to re-style it as attributedText
updateLabel() // with the correct paragraph style to achieve the desired line height.
textSetMode = .text
styleText(newValue)
} }
} }
override public var textAlignment: NSTextAlignment { /// :nodoc:
open override var attributedText: NSAttributedString? {
get { super.attributedText }
set {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
textSetMode = .attributedText
styleAttributedText(newValue)
}
}
/// :nodoc:
open override var textAlignment: NSTextAlignment {
didSet { didSet {
if textAlignment != oldValue { if textAlignment != oldValue {
// Text alignment can be part of our paragraph style, so we may need to // Text alignment can be part of our paragraph style, so we may need to
// re-style when changed // re-style when changed
updateLabel() restyleText()
} }
} }
} }
@ -109,7 +131,7 @@ open class TextView: UITextView, ViewProtocol {
} }
open func updateView() { open func updateView() {
updateLabel() restyleText()
} }
open func updateAccessibility() {} open func updateAccessibility() {}
@ -126,26 +148,59 @@ open class TextView: UITextView, ViewProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Methods // MARK: - Private Methods
//-------------------------------------------------- //--------------------------------------------------
private func updateLabel() { private func restyleText() {
if textSetMode == .text {
//clear the arrays holding actions styleText(text)
accessibilityCustomActions = []
if let text, !text.isEmpty {
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: text,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColor!,
alignment: textAlignment,
lineBreakMode: .byWordWrapping)
//apply any attributes
if let attributes = textAttributes {
mutableText.apply(attributes: attributes)
}
attributedText = mutableText
} else { } else {
attributedText = nil styleAttributedText(attributedText)
}
}
private func styleText(_ newValue: String!) {
defer { invalidateIntrinsicContentSize() }
guard let newValue else {
// We don't need to use attributed text
super.attributedText = nil
super.text = newValue
return
}
accessibilityCustomActions = []
//create the primary string
let mutableText = NSMutableAttributedString.mutableText(for: newValue,
textStyle: textStyle,
useScaledFont: useScaledFont,
textColor: textColorConfiguration.getColor(self),
alignment: textAlignment,
lineBreakMode: .byWordWrapping)
applyAttributes(mutableText)
// Set attributed text to match typography
super.attributedText = mutableText
}
private func styleAttributedText(_ newValue: NSAttributedString?) {
defer { invalidateIntrinsicContentSize() }
guard let newValue = newValue else {
// We don't need any additional styling
super.attributedText = newValue
return
}
let mutableText = NSMutableAttributedString(attributedString: newValue)
applyAttributes(mutableText)
// Modify attributed text to match typography
super.attributedText = mutableText
}
private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) {
if let textAttributes {
mutableAttributedString.apply(attributes: textAttributes)
} }
} }
} }