Merge branch 'feature/tilet' into 'develop'

added initial icon

See merge request BPHV_MIPS/vds_ios!24
This commit is contained in:
Bruce, Matt R 2023-01-10 22:54:04 +00:00
commit 9285d12d29
51 changed files with 905 additions and 29 deletions

View File

@ -58,6 +58,11 @@
EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */; };
EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BEF2968A93600F2FF2E /* TitleLockupEyebrowModel.swift */; };
EA985BF22968B5BB00F2FF2E /* TitleLockupTypography.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF12968B5BB00F2FF2E /* TitleLockupTypography.swift */; };
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF4296C60C000F2FF2E /* Icon.swift */; };
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF6296C665E00F2FF2E /* IconName.swift */; };
EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF8296C710100F2FF2E /* IconColor.swift */; };
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C1C296CD13600F2FF2E /* BundleManager.swift */; };
EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C22296E033A00F2FF2E /* TextArea.swift */; };
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */; };
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEB628ECC03A003B3210 /* ToolTipLabelAttribute.swift */; };
EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAA5EEB828ECD24B003B3210 /* Icons.xcassets */; };
@ -80,7 +85,7 @@
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; };
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
EAC9258C2911C9DE00091998 /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* TextEntryField.swift */; };
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; };
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; };
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; };
EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* Checkbox.swift */; };
@ -165,6 +170,11 @@
EA985BED2968A92400F2FF2E /* TitleLockupSubTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupSubTitleModel.swift; sourceTree = "<group>"; };
EA985BEF2968A93600F2FF2E /* TitleLockupEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupEyebrowModel.swift; sourceTree = "<group>"; };
EA985BF12968B5BB00F2FF2E /* TitleLockupTypography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTypography.swift; sourceTree = "<group>"; };
EA985BF4296C60C000F2FF2E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = "<group>"; };
EA985BF6296C665E00F2FF2E /* IconName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconName.swift; sourceTree = "<group>"; };
EA985BF8296C710100F2FF2E /* IconColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconColor.swift; sourceTree = "<group>"; };
EA985C1C296CD13600F2FF2E /* BundleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleManager.swift; sourceTree = "<group>"; };
EA985C22296E033A00F2FF2E /* TextArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextArea.swift; sourceTree = "<group>"; };
EAA5EEB428ECBFB4003B3210 /* ImageLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageLabelAttribute.swift; sourceTree = "<group>"; };
EAA5EEB628ECC03A003B3210 /* ToolTipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolTipLabelAttribute.swift; sourceTree = "<group>"; };
EAA5EEB828ECD24B003B3210 /* Icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Icons.xcassets; sourceTree = "<group>"; };
@ -187,7 +197,7 @@
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
EAC925872911C9DE00091998 /* TextEntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = "<group>"; };
EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
EAF7F0932899861000B287F5 /* Checkbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
@ -332,10 +342,11 @@
EA4DB2FE28DCBC1900103EE3 /* Badge */,
EA0FC2BE2912D18200DF80B4 /* Buttons */,
EAF7F092289985E200B287F5 /* Checkbox */,
EA985BF3296C609E00F2FF2E /* Icon */,
EA1F265F28B945070033E859 /* RadioSwatch */,
EA3362412892EF700071C351 /* Label */,
EA89200B28B530F0006B9984 /* RadioBox */,
EAF7F11428A1470D00B287F5 /* RadioButton */,
EA1F265F28B945070033E859 /* RadioSwatch */,
EAC925852911C9DE00091998 /* TextFields */,
EA5E304A294CBDBB0082B959 /* TileContainer */,
EA5E3056295105930082B959 /* Tilet */,
@ -394,6 +405,7 @@
EA3361B4288B2A360071C351 /* Classes */ = {
isa = PBXGroup;
children = (
EA985C1C296CD13600F2FF2E /* BundleManager.swift */,
EAF7F0B8289C139800B287F5 /* ColorConfiguration.swift */,
EAF7F09D289AAEC000B287F5 /* Constants.swift */,
EA3361B5288B2A410071C351 /* Control.swift */,
@ -499,6 +511,24 @@
path = RadioBox;
sourceTree = "<group>";
};
EA985BF3296C609E00F2FF2E /* Icon */ = {
isa = PBXGroup;
children = (
EA985BF4296C60C000F2FF2E /* Icon.swift */,
EA985BF8296C710100F2FF2E /* IconColor.swift */,
EA985BF6296C665E00F2FF2E /* IconName.swift */,
);
path = Icon;
sourceTree = "<group>";
};
EA985C21296E032000F2FF2E /* TextArea */ = {
isa = PBXGroup;
children = (
EA985C22296E033A00F2FF2E /* TextArea.swift */,
);
path = TextArea;
sourceTree = "<group>";
};
EAB1D2D028ABEF3100DAE764 /* Typography */ = {
isa = PBXGroup;
children = (
@ -538,18 +568,19 @@
EAC925852911C9DE00091998 /* TextFields */ = {
isa = PBXGroup;
children = (
EAC925862911C9DE00091998 /* TextEntryField */,
EAC925862911C9DE00091998 /* InputField */,
EA985C21296E032000F2FF2E /* TextArea */,
EAC925892911C9DE00091998 /* EntryField */,
);
path = TextFields;
sourceTree = "<group>";
};
EAC925862911C9DE00091998 /* TextEntryField */ = {
EAC925862911C9DE00091998 /* InputField */ = {
isa = PBXGroup;
children = (
EAC925872911C9DE00091998 /* TextEntryField.swift */,
EAC925872911C9DE00091998 /* InputField.swift */,
);
path = TextEntryField;
path = InputField;
sourceTree = "<group>";
};
EAC925892911C9DE00091998 /* EntryField */ = {
@ -717,14 +748,16 @@
EA3361C328902D960071C351 /* Toggle.swift in Sources */,
EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */,
EA89201328B568D8006B9984 /* RadioBox.swift in Sources */,
EAC9258C2911C9DE00091998 /* TextEntryField.swift in Sources */,
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */,
EA3362402892EF6C0071C351 /* Label.swift in Sources */,
EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */,
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */,
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */,
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */,
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
EAC925842911C63100091998 /* Colorable.swift in Sources */,
EA3361C5289030FC0071C351 /* Accessable.swift in Sources */,
@ -762,6 +795,7 @@
EA5E304E294CC7F00082B959 /* VDSColor.swift in Sources */,
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
EAF7F09E289AAEC000B287F5 /* Constants.swift in Sources */,
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */,
EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */,
EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */,
EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */,
@ -774,10 +808,12 @@
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */,
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
EA3361AA288B25E40071C351 /* Disabling.swift in Sources */,
EA3361B6288B2A410071C351 /* Control.swift in Sources */,
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */,
EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */,
EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */,
EAB5FED429267EB300998C17 /* UIView.swift in Sources */,
EA3361AD288B26190071C351 /* DataTrackable.swift in Sources */,
EA33623E2892EE950071C351 /* UIDevice.swift in Sources */,

View File

@ -0,0 +1,61 @@
//
// BundleManager.swift
// VDS
//
// Created by Matt Bruce on 1/9/23.
//
import Foundation
import UIKit
public class BundleManager {
public static var shared = BundleManager()
public var bundles: [Bundle] = []
private var paths: [String] = []
private init(){
bundles.append(Bundle(for: Self.self))
}
private func updateBundles() {
bundles.removeAll()
bundles.append(Bundle(for: Self.self))
paths.forEach({ path in
if let bundle = Bundle(path: path) {
bundles.append(bundle)
}
})
}
public static func register(_ path: String) {
if !shared.paths.contains(where: {$0 == path}) {
if let bundle = Bundle(path: path) {
shared.paths.append(path)
shared.bundles.append(bundle)
}
}
}
}
extension BundleManager {
public func image(for name: String) -> UIImage? {
var foundImage: UIImage?
if let image = UIImage(named: name) {
foundImage = image
} else {
for bundle in bundles {
if let image = UIImage(named: name, in: bundle, with: nil) {
foundImage = image
break
}
}
}
return foundImage
}
}

View File

@ -0,0 +1,127 @@
//
// Icon.swift
// VDS
//
// Created by Matt Bruce on 1/9/23.
//
import Foundation
import UIKit
import VDSColorTokens
import Combine
public enum IconSize: String, CaseIterable {
case xsmall
case small
case medium
case large
case XLarge
public var dimensions: CGSize {
switch self {
case .xsmall:
return .init(width: 12, height: 12)
case .small:
return .init(width: 16, height: 16)
case .medium:
return .init(width: 20, height: 20)
case .large:
return .init(width: 24, height: 24)
case .XLarge:
return .init(width: 28, height: 28)
}
}
}
@objc(VDSIcon)
public class Icon: View {
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private var widthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
private var imageView = UIImageView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.contentMode = .scaleAspectFill
$0.clipsToBounds = true
}
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
open var color: IconColor = .black { didSet { didChange() }}
open var size: IconSize = .medium { didSet { didChange() }}
open var name: IconName? { didSet { didChange() }}
//functions
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func setup() {
super.setup()
addSubview(imageView)
imageView.pinToSuperView()
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: size.dimensions.height)
heightConstraint?.isActive = true
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: size.dimensions.width)
widthConstraint?.isActive = true
backgroundColor = .clear
}
public override func reset() {
super.reset()
color = .black
imageView.image = nil
}
//--------------------------------------------------
// MARK: - State
//--------------------------------------------------
open override func updateView() {
super.updateView()
//get the color for the image
var imageColor = color.value
//ensure the correct color for white/black colors
if surface == .dark && color == IconColor.black {
imageColor = VDSColor.elementsPrimaryOndark
} else if surface == .light && color == IconColor.black {
imageColor = VDSColor.elementsPrimaryOnlight
}
//set the icon dimensions
let dimensions = size.dimensions
heightConstraint?.constant = dimensions.height
widthConstraint?.constant = dimensions.width
//get the image name
//set the image
if let name, let image = getImage(for: name.rawValue) {
setImage(image: image, imageColor: imageColor)
} else {
imageView.image = nil
}
}
private func getImage(for imageName: String) -> UIImage? {
return BundleManager.shared.image(for: imageName)
}
private func setImage(image: UIImage, imageColor: UIColor) {
imageView.image = image.withTintColor(imageColor)
}
}

View File

@ -0,0 +1,90 @@
//
// IconColor.swift
// VDS
//
// Created by Matt Bruce on 1/9/23.
//
import Foundation
import VDSColorTokens
import UIKit
public enum IconColor: String, CaseIterable {
case black
case white
case red
case gray95
case gray85
case gray65
case gray44
case gray20
case gray11
case orange91
case orange46
case orange39
case orange15
case yellow94
case yellow62
case yellow20
case blue91
case blue45
case blue35
case blue13
case green89
case green34
case green26
case green11
public var value: UIColor {
switch self {
case .black:
return VDSColor.paletteBlack
case .white:
return VDSColor.paletteWhite
case .red:
return VDSColor.paletteRed
case .gray95:
return VDSColor.paletteGray95
case .gray85:
return VDSColor.paletteGray85
case .gray65:
return VDSColor.paletteGray65
case .gray44:
return VDSColor.paletteGray44
case .gray20:
return VDSColor.paletteGray20
case .gray11:
return VDSColor.paletteGray11
case .orange91:
return VDSColor.paletteOrange91
case .orange46:
return VDSColor.paletteOrange46
case .orange39:
return VDSColor.paletteOrange39
case .orange15:
return VDSColor.paletteOrange15
case .yellow94:
return VDSColor.paletteYellow94
case .yellow62:
return VDSColor.paletteYellow62
case .yellow20:
return VDSColor.paletteYellow20
case .blue91:
return VDSColor.paletteBlue91
case .blue45:
return VDSColor.paletteBlue45
case .blue35:
return VDSColor.paletteBlue35
case .blue13:
return VDSColor.paletteBlue13
case .green89:
return VDSColor.paletteGreen89
case .green34:
return VDSColor.paletteGreen34
case .green26:
return VDSColor.paletteGreen26
case .green11:
return VDSColor.paletteGreen11
}
}
}

View File

@ -0,0 +1,42 @@
//
// IconName.swift
// VDS
//
// Created by Matt Bruce on 1/9/23.
//
import Foundation
import UIKit
import VDSColorTokens
public struct IconName: RawRepresentable {
public typealias RawValue = String
public var rawValue: String
public init?(rawValue: String) {
self.rawValue = rawValue
}
public init(name: String){
self.rawValue = name
}
internal static let paginationLeftArrow = IconName(name: "pagination-left-arrow")
internal static let paginationRightArrow = IconName(name: "pagination-right-arrow")
public static let checkmark = IconName(name: "checkmark")
internal static let checkmarkBold = IconName(name: "checkmark-bold")
public static let checkmarkAlt = IconName(name: "checkmark-alt")
internal static let checkmarkAltBold = IconName(name: "checkmark-alt-bold")
public static let close = IconName(name: "close")
internal static let closeBold = IconName(name: "close-bold")
public static let error = IconName(name: "error")
internal static let errorBold = IconName(name: "error-bold")
public static let info = IconName(name: "info")
internal static let infoBold = IconName(name: "info-bold")
public static let leftCaret = IconName(name: "left-caret")
internal static let leftCaretBold = IconName(name: "left-caret-bold")
public static let rightCaret = IconName(name: "right-caret")
internal static let rightCaretBold = IconName(name: "right-caret-bold")
public static let warning = IconName(name: "warning")
internal static let warningBold = IconName(name: "warning-bold")
}

View File

@ -42,7 +42,7 @@ open class EntryField: Control, Accessable {
$0.distribution = .fill
}
}()
internal var titleLabel = Label().with {
$0.setContentCompressionResistancePriority(.required, for: .vertical)
$0.attributes = []
@ -68,13 +68,32 @@ open class EntryField: Control, Accessable {
}
}()
internal var containerStackView: UIStackView = {
return UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .horizontal
$0.distribution = .fillProportionally
$0.alignment = .top
}
}()
internal var controlContainerView: UIView = {
return UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
}()
internal var tooltipView: UIView?
internal var icon: Icon = Icon().with {
$0.size = .small
}
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
// Sizes are from InVision design specs.
internal let containerSize = CGSize(width: 45, height: 45)
internal var containerSize: CGSize { CGSize(width: 45, height: 44) }
internal let primaryColorConfig = ViewColorConfiguration().with {
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true)
@ -173,8 +192,21 @@ open class EntryField: Control, Accessable {
heightConstraint?.isActive = true
widthConstraint = containerView.widthAnchor.constraint(equalToConstant: 0)
//get the container this is what is color
//border, internal, etc...
let container = getContainer()
//add ContainerStackView
//this is the horizontal stack that contains
//the left, InputContainer, Icons, Buttons
container.addSubview(containerStackView)
containerStackView.pinToSuperView(.init(top: 12, left: 12, bottom: 12, right: 12))
//add the view to add input fields
containerStackView.addArrangedSubview(controlContainerView)
containerStackView.addArrangedSubview(icon)
stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(container)
stackView.addArrangedSubview(errorLabel)
@ -345,7 +377,12 @@ open class EntryField: Control, Accessable {
errorLabel.surface = surface
errorLabel.disabled = disabled
errorLabel.isHidden = false
icon.name = .error
icon.color = .black
icon.surface = surface
icon.isHidden = disabled
} else {
icon.isHidden = true
errorLabel.isHidden = true
}
}

View File

@ -11,14 +11,12 @@ import VDSColorTokens
import VDSFormControlsTokens
import Combine
public enum TextEntryFieldType: String, CaseIterable {
public enum InputFieldType: String, CaseIterable {
case text, number, calendar, inlineAction, password, creditCard, tel, date, securityCode
}
@objc(VDSTextEntryField)
public class TextEntryField: TextEntryFieldBase{}
open class TextEntryFieldBase: EntryField {
@objc(VDSInputField)
public class InputField: EntryField, UITextFieldDelegate {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -37,7 +35,7 @@ open class TextEntryFieldBase: EntryField {
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
internal var containerStackView: UIStackView = {
internal var inputFieldStackView: UIStackView = {
return UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .horizontal
@ -50,7 +48,7 @@ open class TextEntryFieldBase: EntryField {
// MARK: - Public Properties
//--------------------------------------------------
open var type: TextEntryFieldType = .text { didSet { didChange() }}
open var type: InputFieldType = .text { didSet { didChange() }}
var _showError: Bool = false
open override var showError: Bool {
@ -94,6 +92,16 @@ open class TextEntryFieldBase: EntryField {
$0.typograpicalStyle = .BodySmall
}
private var textField = UITextField().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.font = TypographicalStyle.BodyLarge.font
}
public var textFieldTextColorConfiguration: AnyColorable = ViewColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: true)
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)
}.eraseToAnyColorable()
internal var minWidthConstraint: NSLayoutConstraint?
//--------------------------------------------------
@ -104,7 +112,18 @@ open class TextEntryFieldBase: EntryField {
minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0)
minWidthConstraint?.isActive = true
controlContainerView.addSubview(textField)
textField.pinToSuperView()
textField.heightAnchor.constraint(equalToConstant: 20).isActive = true
textField
.textPublisher
.sink { [weak self] text in
self?.value = text
self?.sendActions(for: .valueChanged)
}.store(in: &subscribers)
stackView.addArrangedSubview(successLabel)
stackView.setCustomSpacing(8, after: successLabel)
@ -117,6 +136,9 @@ open class TextEntryFieldBase: EntryField {
public override func reset() {
super.reset()
textField.text = ""
textField.delegate = self
successLabel.reset()
successLabel.textPosition = .left
successLabel.typograpicalStyle = .BodySmall
@ -128,8 +150,8 @@ open class TextEntryFieldBase: EntryField {
}
open override func getContainer() -> UIView {
containerStackView.addArrangedSubview(containerView)
return containerStackView
inputFieldStackView.addArrangedSubview(containerView)
return inputFieldStackView
}
//--------------------------------------------------
@ -138,6 +160,9 @@ open class TextEntryFieldBase: EntryField {
open override func updateView() {
super.updateView()
textField.isEnabled = isEnabled
textField.textColor = textFieldTextColorConfiguration.getColor(self)
//show error or success
if showError, let _ = errorText {
successLabel.isHidden = true
@ -148,10 +173,13 @@ open class TextEntryFieldBase: EntryField {
successLabel.disabled = disabled
successLabel.isHidden = false
errorLabel.isHidden = true
icon.name = .checkmarkAlt
icon.color = .black
icon.surface = surface
icon.isHidden = disabled
} else {
icon.isHidden = true
successLabel.isHidden = true
}
//set the width constraints
@ -175,19 +203,20 @@ open class TextEntryFieldBase: EntryField {
//set the helper label position
if helperText != nil {
if helperTextPlacement == .right {
containerStackView.spacing = 12
containerStackView.distribution = .fillEqually
containerStackView.addArrangedSubview(helperLabel)
inputFieldStackView.spacing = 12
inputFieldStackView.distribution = .fillEqually
inputFieldStackView.addArrangedSubview(helperLabel)
} else {
containerStackView.spacing = 0
containerStackView.distribution = .fill
inputFieldStackView.spacing = 0
inputFieldStackView.distribution = .fill
stackView.addArrangedSubview(helperLabel)
}
}
}
}
extension TextEntryFieldType {
extension InputFieldType {
var width: CGFloat {
switch self {
case .inlineAction:

View File

@ -0,0 +1,142 @@
//
// TextArea.swift
// VDS
//
// Created by Matt Bruce on 1/10/23.
//
import Foundation
import Foundation
import UIKit
import VDSColorTokens
import VDSFormControlsTokens
import Combine
@objc(VDSTextArea)
public class TextArea: EntryField {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init() {
super.init(frame: .zero)
}
public override init(frame: CGRect) {
super.init(frame: .zero)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
internal var inputFieldStackView: UIStackView = {
return UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .horizontal
$0.distribution = .fill
$0.spacing = 12
}
}()
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
override var containerSize: CGSize { CGSize(width: 45, height: 88) }
private var textView = UITextView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.font = TypographicalStyle.BodyLarge.font
$0.sizeToFit()
$0.isScrollEnabled = false
}
public var textViewTextColorConfiguration: AnyColorable = ViewColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: true)
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)
}.eraseToAnyColorable()
internal var minWidthConstraint: NSLayoutConstraint?
internal var textViewHeightConstraint: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func setup() {
super.setup()
minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0)
minWidthConstraint?.isActive = true
controlContainerView.addSubview(textView)
textView.pinToSuperView()
textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 64)
textViewHeightConstraint?.isActive = true
backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success)
borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success)
textView.delegate = self
}
public override func reset() {
super.reset()
textView.text = ""
}
open override func getContainer() -> UIView {
inputFieldStackView.addArrangedSubview(containerView)
return inputFieldStackView
}
//--------------------------------------------------
// MARK: - State
//--------------------------------------------------
open override func updateView() {
super.updateView()
textView.isEditable = isEnabled
textView.textColor = textViewTextColorConfiguration.getColor(self)
//set the width constraints
if let width {
widthConstraint?.constant = width
widthConstraint?.isActive = true
minWidthConstraint?.isActive = false
} else {
minWidthConstraint?.constant = containerSize.width
widthConstraint?.isActive = false
minWidthConstraint?.isActive = true
}
}
}
extension TextArea: UITextViewDelegate {
//--------------------------------------------------
// MARK: - UITextViewDelegate
//--------------------------------------------------
public func textViewDidChange(_ textView: UITextView) {
//dynamic textView Height sizing based on Figma
//if you want it to work "as-is" delete this code
//since it will autogrow with the current settings
if let textViewHeightConstraint, textView.isEditable {
let height = textView.frame.size.height
let constraintHeight = textViewHeightConstraint.constant
if height > constraintHeight {
if height > 64 && height < 152 {
textViewHeightConstraint.constant = 152
} else if height > 152 {
textViewHeightConstraint.constant = 328
} else {
textViewHeightConstraint.constant = 64
}
}
}
//setting the value and firing control event
value = textView.text
sendActions(for: .valueChanged)
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "checkmark-alt-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M10.8,20.2c-5.2,0-9.4-4.2-9.4-9.4c0-5.2,4.2-9.4,9.4-9.4c5.2,0,9.4,4.2,9.4,9.4c0,0,0,0,0,0C20.2,16,16,20.2,10.8,20.2z
M10.8,3.4c-4.1,0-7.4,3.3-7.4,7.4s3.3,7.4,7.4,7.4c4.1,0,7.4-3.3,7.4-7.4c0,0,0,0,0,0C18.2,6.7,14.9,3.4,10.8,3.4z M15.1,9.1
l-1.4-1.4l-4,4l-1.7-1.7l-1.4,1.4l3.1,3.1L15.1,9.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 664 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "checkmark-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M8,19.1l-7-7l2.5-2.5L8,14L18.1,3.8l2.5,2.5L8,19.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 423 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "checkmark.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6"><path d="M19.74,5.29,7.88,17.15,1.74,11l.84-.84,5.3,5.31,11-11Z"/></svg>

After

Width:  |  Height:  |  Size: 169 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "close-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M12.2,10.8l6.8,6.8L17.6,19l-6.8-6.8L4,19l-1.4-1.4l6.8-6.8L2.6,4L4,2.6l6.8,6.8l6.8-6.8L19,4L12.2,10.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "close.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6"><path d="M11.59,10.8l7.11,7.1-.8.8-7.1-7.11L3.7,18.7l-.8-.8L10,10.8,2.9,3.7l.8-.8L10.8,10,17.9,2.9l.8.8Z"/></svg>

After

Width:  |  Height:  |  Size: 210 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "down-caret-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12">
<g id="Layer_62" data-name="Layer 62">
<polygon points="6 9.687 0.518 4.206 1.932 2.791 6 6.859 10.067 2.791 11.481 4.206 6 9.687"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 214 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "down-caret.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,3 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<polygon points="10.8 15.71 1.8 6.71 2.62 5.89 10.8 14.07 18.98 5.89 19.8 6.71 10.8 15.71"/>
</svg>

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "error-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#010101;}
</style>
<path class="st0" d="M19.4,8.8l-6.6-6.6c-1.1-1.1-2.9-1.1-4,0L2.2,8.8c-1.1,1.1-1.1,2.9,0,4l6.6,6.6c1.1,1.1,2.9,1.1,4,0
c0,0,0,0,0,0l6.6-6.6C20.5,11.7,20.5,9.9,19.4,8.8z M18,11.4L11.4,18c-0.3,0.3-0.9,0.3-1.2,0l-6.6-6.6c-0.3-0.3-0.3-0.9,0-1.2
l6.6-6.6c0.3-0.3,0.9-0.3,1.2,0l6.6,6.6C18.3,10.5,18.3,11.1,18,11.4z M9.9,13.4h1.7v1.7H9.9V13.4z M9.9,6.5h1.7V9l-0.6,2.6h-0.6
L9.9,9V6.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 797 B

View File

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "info-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,10 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<defs>
<style>
.cls-1 {
fill: #010101;
}
</style>
</defs>
<path class="cls-1" d="M10.80011,1.36129a9.43848,9.43848,0,1,0,9.43848,9.43848A9.43847,9.43847,0,0,0,10.80011,1.36129Zm0,16.877a7.43848,7.43848,0,1,1,7.43848-7.43848A7.43849,7.43849,0,0,1,10.80011,18.23825ZM11.625,7.45849H9.95V5.78344h1.675ZM9.95834,9.11663H11.65v6.69989H9.95834Z"/>
</svg>

After

Width:  |  Height:  |  Size: 481 B

View File

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 390 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "left-caret-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M14.1,20.7l-9.9-9.9l9.9-9.9l2.5,2.5l-7.3,7.3l7.3,7.3L14.1,20.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 436 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "left-caret.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,3 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<polygon points="14.89 19.8 5.89 10.799 14.89 1.8 15.71 2.619 7.53 10.799 15.71 18.981 14.89 19.8"/>
</svg>

After

Width:  |  Height:  |  Size: 208 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "pagination-left-arrow.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M19.8,11.7h-15l7.1,7.1L10.7,20l-9.3-9.2l9.3-9.2l1.3,1.3L4.8,9.9h15L19.8,11.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "pagination-left-caret.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_39" data-name="Layer 39" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<polygon points="14.74336 20.10078 5.44258 10.8 14.74336 1.49922 16.15742 2.91328 8.2707 10.8 16.15742 18.68672 14.74336 20.10078"/>
</svg>

After

Width:  |  Height:  |  Size: 280 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "pagination-right-arrow.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,3 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<path d="M20.26723,10.80317,10.94378,20.044,9.6764,18.7643l7.12223-7.05674H1.8014v-1.8H16.808L9.68256,2.84378l1.26738-1.278Z"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "pagination-right-caret.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_39" data-name="Layer 39" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<polygon points="6.85664 20.10127 5.44258 18.68721 13.3293 10.79951 5.44258 2.91279 6.85664 1.49873 16.15742 10.79951 6.85664 20.10127"/>
</svg>

After

Width:  |  Height:  |  Size: 285 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "right-caret-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 21.6 21.6" style="enable-background:new 0 0 21.6 21.6;" xml:space="preserve">
<path d="M7.6,20.7L5,18.1l7.3-7.3L5,3.5l2.5-2.5l9.9,9.9L7.6,20.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 429 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "warning-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,3 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<path d="M19.90265,15.566l-6.936-12.03357a2.50126,2.50126,0,0,0-4.34088-.001L1.69659,15.566a2.51054,2.51054,0,0,0,2.17432,3.75989H17.7312A2.50926,2.50926,0,0,0,19.90265,15.566Zm-1.734,1.5055a.51007.51007,0,0,1-.43933.25482H3.87286a.51076.51076,0,0,1-.44323-.76251L10.3598,4.52633a.50217.50217,0,0,1,.87183,0l6.938,12.03552A.51553.51553,0,0,1,18.16864,17.0715ZM9.95,14.367h1.7V16.05H9.95Zm0-6.817h1.7v2.49048l-.56951,2.635H10.511L9.95,10.04049Z"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "warning.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,3 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.6 21.6">
<path d="M19.52557,15.78473,12.588,3.74951a2.0643,2.0643,0,0,0-3.584-.001L2.0733,15.78668a2.07277,2.07277,0,0,0,1.79688,3.10358H17.73157a2.07289,2.07289,0,0,0,1.794-3.10553ZM18.548,17.2926a.9494.9494,0,0,1-.81738.47266H3.87115a.94838.94838,0,0,1-.82226-1.419L9.97961,4.30811a.9396.9396,0,0,1,1.63184,0L18.551,16.34625A.95147.95147,0,0,1,18.548,17.2926ZM9.95,14.367h1.7V16.05H9.95Zm0-6.817h1.7v2.49048l-.56951,2.635H10.511l-.561-2.635Z"/>
</svg>

After

Width:  |  Height:  |  Size: 545 B