refactored out TextView
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
c75064e84e
commit
6cd8b31985
@ -68,6 +68,7 @@
|
||||
EA5F86C82A1BD99100BC83E4 /* TabModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5F86C72A1BD99100BC83E4 /* TabModel.swift */; };
|
||||
EA5F86CC2A1D28B500BC83E4 /* ReleaseNotes.txt in Resources */ = {isa = PBXBuildFile; fileRef = EA5F86CB2A1D28B500BC83E4 /* ReleaseNotes.txt */; };
|
||||
EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5F86CF2A1F936100BC83E4 /* TabsContainer.swift */; };
|
||||
EA6F330E2B911E9000BACAB9 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6F330D2B911E9000BACAB9 /* TextView.swift */; };
|
||||
EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */; };
|
||||
EA8141102A127066004F60D2 /* UIColor+VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */; };
|
||||
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; };
|
||||
@ -236,6 +237,7 @@
|
||||
EA5F86C72A1BD99100BC83E4 /* TabModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabModel.swift; sourceTree = "<group>"; };
|
||||
EA5F86CB2A1D28B500BC83E4 /* ReleaseNotes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ReleaseNotes.txt; sourceTree = "<group>"; };
|
||||
EA5F86CF2A1F936100BC83E4 /* TabsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsContainer.swift; sourceTree = "<group>"; };
|
||||
EA6F330D2B911E9000BACAB9 /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; };
|
||||
EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = "<group>"; };
|
||||
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+VDSColor.swift"; sourceTree = "<group>"; };
|
||||
EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = "<group>"; };
|
||||
@ -717,6 +719,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA985C22296E033A00F2FF2E /* TextArea.swift */,
|
||||
EA6F330D2B911E9000BACAB9 /* TextView.swift */,
|
||||
186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */,
|
||||
);
|
||||
path = TextArea;
|
||||
@ -1059,6 +1062,7 @@
|
||||
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
|
||||
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
|
||||
EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */,
|
||||
EA6F330E2B911E9000BACAB9 /* TextView.swift in Sources */,
|
||||
EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */,
|
||||
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */,
|
||||
EAD0688E2A55F819002E3A2D /* Loader.swift in Sources */,
|
||||
|
||||
@ -35,7 +35,6 @@ open class TextArea: EntryFieldBase {
|
||||
//--------------------------------------------------
|
||||
internal var minWidthConstraint: NSLayoutConstraint?
|
||||
internal var textViewHeightConstraint: NSLayoutConstraint?
|
||||
internal var allowCharCount: Int = 0
|
||||
|
||||
internal var inputFieldStackView: UIStackView = {
|
||||
return UIStackView().with {
|
||||
@ -204,11 +203,9 @@ open class TextArea: EntryFieldBase {
|
||||
minWidthConstraint?.isActive = true
|
||||
}
|
||||
|
||||
let characterError = getCharacterCounterText()
|
||||
if let maxLength, maxLength > 0 {
|
||||
// allow - 20% of character limit
|
||||
let overflowLimit = Double(maxLength) * 0.20
|
||||
allowCharCount = Int(overflowLimit) + maxLength
|
||||
characterCounterLabel.text = getCharacterCounterText()
|
||||
characterCounterLabel.text = characterError
|
||||
} else {
|
||||
characterCounterLabel.text = ""
|
||||
}
|
||||
@ -245,22 +242,23 @@ open class TextArea: EntryFieldBase {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
private func getCharacterCounterText() -> String {
|
||||
private func getCharacterCounterText() -> String? {
|
||||
let count = textView.text.count
|
||||
let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)"
|
||||
if ((maxLength ?? 0) > 0) {
|
||||
if (count > (maxLength ?? 0)) {
|
||||
if let maxLength, maxLength > 0 {
|
||||
if count > maxLength {
|
||||
showInternalError = true
|
||||
internalErrorText = "You have exceeded the character limit."
|
||||
return countStr
|
||||
} else {
|
||||
|
||||
showInternalError = false
|
||||
internalErrorText = nil
|
||||
return ("\(countStr)" + "/" + "\(maxLength ?? 0)")
|
||||
return ("\(countStr)" + "/" + "\(maxLength)")
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
showInternalError = false
|
||||
internalErrorText = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,7 +301,11 @@ extension TextArea: UITextViewDelegate {
|
||||
}
|
||||
|
||||
//The exceeding characters will be highlighted to help users correct their entry.
|
||||
if ((maxLength ?? 0) > 0) {
|
||||
if let maxLength, maxLength > 0 {
|
||||
// allow - 20% of character limit
|
||||
let overflowLimit = Double(maxLength) * 0.20
|
||||
let allowCharCount = Int(overflowLimit) + maxLength
|
||||
|
||||
if textView.text.count <= allowCharCount {
|
||||
highlightCharacterOverflow()
|
||||
|
||||
@ -319,146 +321,5 @@ extension TextArea: UITextViewDelegate {
|
||||
text = textView.text
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Will move this into a new file, need to talk with Scott/Kyle
|
||||
open class TextView: UITextView, ViewProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero, textContainer: nil)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect, textContainer: NSTextContainer?) {
|
||||
super.init(frame: frame, textContainer: textContainer)
|
||||
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 var isEnabled: Bool = true { didSet { setNeedsUpdate() } }
|
||||
|
||||
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 { }
|
||||
}
|
||||
|
||||
override public var text: String! {
|
||||
get { super.text }
|
||||
set {
|
||||
super.text = newValue
|
||||
updateLabel()
|
||||
}
|
||||
}
|
||||
|
||||
override public 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
|
||||
updateLabel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open func initialSetup() {
|
||||
if !initialSetupPerformed {
|
||||
backgroundColor = .clear
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
accessibilityCustomActions = []
|
||||
setup()
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open func setup() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
open func updateView() {
|
||||
updateLabel()
|
||||
}
|
||||
|
||||
open func updateAccessibility() {}
|
||||
|
||||
open func reset() {
|
||||
shouldUpdateView = false
|
||||
surface = .light
|
||||
text = nil
|
||||
accessibilityCustomActions = []
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
private func updateLabel() {
|
||||
|
||||
//clear the arrays holding actions
|
||||
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 {
|
||||
attributedText = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
150
VDS/Components/TextFields/TextArea/TextView.swift
Normal file
150
VDS/Components/TextFields/TextArea/TextView.swift
Normal file
@ -0,0 +1,150 @@
|
||||
//
|
||||
// TextView.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 2/29/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDSColorTokens
|
||||
|
||||
/// Will move this into a new file, need to talk with Scott/Kyle
|
||||
open class TextView: UITextView, ViewProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero, textContainer: nil)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect, textContainer: NSTextContainer?) {
|
||||
super.init(frame: frame, textContainer: textContainer)
|
||||
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 var isEnabled: Bool = true { didSet { setNeedsUpdate() } }
|
||||
|
||||
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 { }
|
||||
}
|
||||
|
||||
override public var text: String! {
|
||||
get { super.text }
|
||||
set {
|
||||
super.text = newValue
|
||||
updateLabel()
|
||||
}
|
||||
}
|
||||
|
||||
override public 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
|
||||
updateLabel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open func initialSetup() {
|
||||
if !initialSetupPerformed {
|
||||
backgroundColor = .clear
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
accessibilityCustomActions = []
|
||||
setup()
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open func setup() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
open func updateView() {
|
||||
updateLabel()
|
||||
}
|
||||
|
||||
open func updateAccessibility() {}
|
||||
|
||||
open func reset() {
|
||||
shouldUpdateView = false
|
||||
surface = .light
|
||||
text = nil
|
||||
accessibilityCustomActions = []
|
||||
shouldUpdateView = true
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
private func updateLabel() {
|
||||
|
||||
//clear the arrays holding actions
|
||||
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 {
|
||||
attributedText = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user