Merge branch 'vasavk/dropdownSelect' into 'develop'
VDS Brand 3.0 Dropdown Select for IOS See merge request BPHV_MIPS/vds_ios!201
This commit is contained in:
commit
e72a94b102
@ -13,9 +13,12 @@
|
||||
18450CF12BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */; };
|
||||
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; };
|
||||
186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */; };
|
||||
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; };
|
||||
186D13CF2BBC36EF00986B53 /* DropdownSelectChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */; };
|
||||
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; };
|
||||
18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; };
|
||||
18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; };
|
||||
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; };
|
||||
18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; };
|
||||
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
||||
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; };
|
||||
@ -202,9 +205,12 @@
|
||||
18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BreadcrumbsChangeLog.txt; sourceTree = "<group>"; };
|
||||
1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItemModel.swift; sourceTree = "<group>"; };
|
||||
186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = "<group>"; };
|
||||
186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = "<group>"; };
|
||||
186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = "<group>"; };
|
||||
18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = "<group>"; };
|
||||
18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = "<group>"; };
|
||||
18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = "<group>"; };
|
||||
18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = "<group>"; };
|
||||
18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = "<group>"; };
|
||||
445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = "<group>"; };
|
||||
@ -407,6 +413,16 @@
|
||||
path = CarouselScrollbar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
186D13C92BBA8A3500986B53 /* DropdownSelect */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */,
|
||||
18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */,
|
||||
186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */,
|
||||
);
|
||||
path = DropdownSelect;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
18A65A002B96E7E1006602CC /* Breadcrumbs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -569,6 +585,7 @@
|
||||
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
||||
1808BEBA2BA41B1D00129230 /* CarouselScrollbar */,
|
||||
EAF7F092289985E200B287F5 /* Checkbox */,
|
||||
186D13C92BBA8A3500986B53 /* DropdownSelect */,
|
||||
EA985BF3296C609E00F2FF2E /* Icon */,
|
||||
EA3362412892EF700071C351 /* Label */,
|
||||
44604AD529CE195300E62B51 /* Line */,
|
||||
@ -1058,6 +1075,7 @@
|
||||
EAEEECA02B1F908200531FC2 /* BadgeIndicatorChangeLog.txt in Resources */,
|
||||
EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */,
|
||||
EAEEECA92B1F969700531FC2 /* TooltipChangeLog.txt in Resources */,
|
||||
186D13CF2BBC36EF00986B53 /* DropdownSelectChangeLog.txt in Resources */,
|
||||
EAEEEC9C2B1F8F0700531FC2 /* TextLinkCaretChangeLog.txt in Resources */,
|
||||
EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */,
|
||||
71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */,
|
||||
@ -1117,6 +1135,7 @@
|
||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||
EA0D1C412A6AD61C00E5C127 /* Typography+Additional.swift in Sources */,
|
||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||
18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */,
|
||||
EAACB89A2B927108006A3869 /* Valuing.swift in Sources */,
|
||||
EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */,
|
||||
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,
|
||||
@ -1180,6 +1199,7 @@
|
||||
1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */,
|
||||
EAF978212A99035B00C2FEA9 /* Enabling.swift in Sources */,
|
||||
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */,
|
||||
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */,
|
||||
EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */,
|
||||
EA0B180A2AA78F9000F2D0CD /* UIEdgeInsets.swift in Sources */,
|
||||
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */,
|
||||
|
||||
22
VDS/Components/DropdownSelect/DropdownOptionModel.swift
Normal file
22
VDS/Components/DropdownSelect/DropdownOptionModel.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// DropdownOptionModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Kanamarlapudi, Vasavi on 03/04/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension DropdownSelect {
|
||||
public struct DropdownOptionModel {
|
||||
|
||||
/// Text that goes as option to DropdownSelect
|
||||
public var text: String
|
||||
public var value: String
|
||||
|
||||
public init(text: String, value: String? = nil) {
|
||||
self.text = text
|
||||
self.value = value ?? text
|
||||
}
|
||||
}
|
||||
}
|
||||
290
VDS/Components/DropdownSelect/DropdownSelect.swift
Normal file
290
VDS/Components/DropdownSelect/DropdownSelect.swift
Normal file
@ -0,0 +1,290 @@
|
||||
//
|
||||
// DropdownSelect.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Kanamarlapudi, Vasavi on 28/03/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
||||
@objc(VDSDropdownSelect)
|
||||
open class DropdownSelect: EntryFieldBase {
|
||||
//--------------------------------------------------
|
||||
// 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: - Public Properties
|
||||
//--------------------------------------------------
|
||||
/// If true, the label will be displayed inside the dropdown containerView. Otherwise, the label will be above the dropdown containerView like a normal text input.
|
||||
open var showInlineLabel: Bool = false { didSet { setNeedsUpdate() }}
|
||||
|
||||
/// Allows unique ID to be passed to the element.
|
||||
open var selectId: Int? { didSet { setNeedsUpdate() }}
|
||||
|
||||
/// Current SelectedItem
|
||||
open var selectedItem: DropdownOptionModel? {
|
||||
guard let selectId else { return nil }
|
||||
return options[selectId]
|
||||
}
|
||||
|
||||
/// Array of options to show
|
||||
open var options: [DropdownOptionModel] = [] { didSet { setNeedsUpdate() }}
|
||||
|
||||
/// A callback when the selected option changes. Passes parameters (option).
|
||||
open var onItemSelected: ((Int, DropdownOptionModel) -> Void)?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
internal var minWidthDefault = 66.0
|
||||
internal var minWidthInlineLabel = 102.0
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
open var inlineDisplayLabel = Label().with {
|
||||
$0.textAlignment = .left
|
||||
$0.textStyle = .boldBodyLarge
|
||||
$0.lineBreakMode = .byCharWrapping
|
||||
$0.sizeToFit()
|
||||
}
|
||||
|
||||
open var selectedOptionLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textAlignment = .left
|
||||
$0.textStyle = .bodyLarge
|
||||
$0.lineBreakMode = .byCharWrapping
|
||||
}
|
||||
|
||||
open var dropdownField = UITextField().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.tintColor = UIColor.clear
|
||||
$0.font = TextStyle.bodyLarge.font
|
||||
}
|
||||
|
||||
open var optionsPicker = UIPickerView()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var inlineWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
//--------------------------------------------------
|
||||
internal override var containerSize: CGSize { CGSize(width: showInlineLabel ? minWidthInlineLabel : width ?? minWidthDefault, height: 44) }
|
||||
|
||||
internal let iconColorConfiguration = ControlColorConfiguration().with {
|
||||
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .error)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
accessibilityLabel = "Dropdown Select"
|
||||
|
||||
// stackview for controls in EntryFieldBase.controlContainerView
|
||||
let controlStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .horizontal
|
||||
$0.spacing = VDSFormControls.spaceInset
|
||||
}
|
||||
controlContainerView.addSubview(controlStackView)
|
||||
controlStackView.pinToSuperView()
|
||||
|
||||
controlStackView.addArrangedSubview(dropdownField)
|
||||
controlStackView.addArrangedSubview(inlineDisplayLabel)
|
||||
controlStackView.addArrangedSubview(selectedOptionLabel)
|
||||
|
||||
controlStackView.setCustomSpacing(0, after: dropdownField)
|
||||
controlStackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: inlineDisplayLabel)
|
||||
controlStackView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: selectedOptionLabel)
|
||||
dropdownField.width(0)
|
||||
inlineWidthConstraint = inlineDisplayLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0)
|
||||
inlineWidthConstraint?.isActive = true
|
||||
|
||||
// setting color config
|
||||
inlineDisplayLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable()
|
||||
selectedOptionLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable()
|
||||
|
||||
// Options PickerView
|
||||
optionsPicker.delegate = self
|
||||
optionsPicker.dataSource = self
|
||||
optionsPicker.isHidden = true
|
||||
dropdownField.inputView = optionsPicker
|
||||
dropdownField.inputAccessoryView = {
|
||||
let inputToolbar = UIToolbar().with {
|
||||
$0.barStyle = .default
|
||||
$0.isTranslucent = true
|
||||
$0.items=[
|
||||
UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil),
|
||||
UIBarButtonItem(title: "Done", style: UIBarButtonItem.Style.done, target: self, action: #selector(pickerDoneClicked))
|
||||
]
|
||||
}
|
||||
inputToolbar.sizeToFit()
|
||||
return inputToolbar
|
||||
}()
|
||||
|
||||
// tap gesture
|
||||
containerStackView
|
||||
.publisher(for: UITapGestureRecognizer())
|
||||
.sink { [weak self] _ in
|
||||
self?.launchPicker()
|
||||
}
|
||||
.store(in: &subscribers)
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
updateInlineLabel()
|
||||
|
||||
dropdownField.isUserInteractionEnabled = readOnly ? false : true
|
||||
selectedOptionLabel.surface = surface
|
||||
selectedOptionLabel.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
|
||||
inlineDisplayLabel.textStyle = .boldBodyLarge
|
||||
selectedOptionLabel.textStyle = .bodyLarge
|
||||
showInlineLabel = false
|
||||
options = []
|
||||
selectId = nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func updateTitleLabel() {
|
||||
|
||||
//update the local vars for the label since we no long have a model
|
||||
var attributes: [any LabelAttributeModel] = []
|
||||
var updatedLabelText = labelText
|
||||
|
||||
updatedLabelText = showInlineLabel ? "" : updatedLabelText
|
||||
|
||||
if let oldText = updatedLabelText, !required, !oldText.hasSuffix("Optional") {
|
||||
let optionColorAttr = ColorLabelAttribute(location: oldText.count + 2,
|
||||
length: 8,
|
||||
color: secondaryColorConfiguration.getColor(self))
|
||||
|
||||
updatedLabelText = showInlineLabel ? "Optional" : "\(oldText) Optional"
|
||||
attributes.append(optionColorAttr)
|
||||
}
|
||||
|
||||
if let tooltipModel {
|
||||
attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self))
|
||||
}
|
||||
|
||||
titleLabel.text = updatedLabelText
|
||||
titleLabel.attributes = attributes
|
||||
titleLabel.surface = surface
|
||||
titleLabel.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
open func updateInlineLabel() {
|
||||
|
||||
inlineWidthConstraint?.isActive = false
|
||||
|
||||
/// inline label text and selected option text separated by ':'
|
||||
if let labelText, !labelText.isEmpty {
|
||||
inlineDisplayLabel.text = showInlineLabel ? (labelText + ":") : ""
|
||||
} else {
|
||||
inlineDisplayLabel.text = showInlineLabel ? labelText : ""
|
||||
}
|
||||
inlineDisplayLabel.surface = surface
|
||||
inlineDisplayLabel.isEnabled = isEnabled
|
||||
|
||||
/// Update width as per updated text size
|
||||
inlineWidthConstraint = inlineDisplayLabel.widthAnchor.constraint(equalToConstant: inlineDisplayLabel.intrinsicContentSize.width)
|
||||
inlineWidthConstraint?.isActive = true
|
||||
|
||||
if let selectId, selectId < options.count {
|
||||
updateSelectedOptionLabel(option: options[selectId])
|
||||
}
|
||||
}
|
||||
|
||||
open func updateSelectedOptionLabel(option: DropdownOptionModel? = nil) {
|
||||
selectedOptionLabel.text = option?.text ?? ""
|
||||
value = option?.value
|
||||
}
|
||||
|
||||
open override func updateErrorLabel() {
|
||||
super.updateErrorLabel()
|
||||
if !showError && !hasInternalError {
|
||||
icon.name = .downCaret
|
||||
}
|
||||
icon.surface = surface
|
||||
icon.isHidden = readOnly ? true : false
|
||||
icon.color = iconColorConfiguration.getColor(self)
|
||||
}
|
||||
|
||||
@objc open func pickerDoneClicked() {
|
||||
optionsPicker.isHidden = true
|
||||
dropdownField.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - UIPickerView Delegate & Datasource
|
||||
//--------------------------------------------------
|
||||
extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
|
||||
internal func launchPicker() {
|
||||
if optionsPicker.isHidden {
|
||||
dropdownField.becomeFirstResponder()
|
||||
} else {
|
||||
dropdownField.resignFirstResponder()
|
||||
}
|
||||
optionsPicker.isHidden = !optionsPicker.isHidden
|
||||
}
|
||||
|
||||
public func numberOfComponents(in pickerView: UIPickerView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
return options.count
|
||||
}
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
guard options.count > row else { return nil }
|
||||
return options[row].text
|
||||
}
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||
guard options.count > row else { return }
|
||||
selectId = row
|
||||
updateSelectedOptionLabel(option: options[row])
|
||||
self.onItemSelected?(row, options[row])
|
||||
}
|
||||
}
|
||||
45
VDS/Components/DropdownSelect/DropdownSelectChangeLog.txt
Normal file
45
VDS/Components/DropdownSelect/DropdownSelectChangeLog.txt
Normal file
@ -0,0 +1,45 @@
|
||||
MM/DD/YYYY
|
||||
----------------
|
||||
Initial Brand 3.0 handoff
|
||||
|
||||
12/27/2021
|
||||
----------------
|
||||
- Removed Max Width, Increased Min width.
|
||||
- Updated the tokens with FormControl tokens
|
||||
|
||||
02/24/2022
|
||||
----------------
|
||||
- Replaced Error and Caret Down Non-Scaling icons with VDS Icon.
|
||||
|
||||
05/02/2022
|
||||
----------------
|
||||
- Anatomy: Noted that Label and Inline Label are optional within the code
|
||||
|
||||
07/27/2022
|
||||
----------------
|
||||
- Updated Dropdown Select Configurations to include Background Transparent Boolean.
|
||||
|
||||
08/10/2022
|
||||
----------------
|
||||
- Updated surface prop from inverted to light and dark
|
||||
|
||||
11/30/2022
|
||||
----------------
|
||||
- Added "(web only)" to any instance of "keyboard focus"
|
||||
|
||||
12/13/2022
|
||||
----------------
|
||||
- Replaced form border and focus border pixel values and styles & spacing with tokens.
|
||||
|
||||
01/19/2023
|
||||
----------------
|
||||
- Added Tooltip and Optional Indicator to Anatomy Updated Specs to use new SPEC Templates and SPEC DOC Components.
|
||||
- Added “Option List” and artwork to Anatomy.
|
||||
|
||||
04/12/2023
|
||||
----------------
|
||||
- Updated hex colors for updated feedback tokens in error states.
|
||||
|
||||
12/27/23
|
||||
----------------
|
||||
- Removed Web/App Parity Discrepancies section
|
||||
@ -51,6 +51,8 @@ extension Icon {
|
||||
public static let checkmark = Name(name: "checkmark")
|
||||
public static let checkmarkAlt = Name(name: "checkmark-alt")
|
||||
public static let close = Name(name: "close")
|
||||
public static let downCaret = Name(name: "down-caret")
|
||||
public static let downCaretBold = Name(name: "down-caret-bold")
|
||||
public static let error = Name(name: "error")
|
||||
public static let info = Name(name: "info")
|
||||
public static let multipleDocuments = Name(name: "multiple-documents")
|
||||
|
||||
@ -110,6 +110,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
$0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
||||
$0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error)
|
||||
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error])
|
||||
}
|
||||
|
||||
internal var readOnlyBorderColorConfiguration = ControlColorConfiguration().with {
|
||||
@ -185,33 +186,24 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// Override this to conveniently get/set the textfield(s).
|
||||
open var text: String? {
|
||||
get { nil }
|
||||
set { fatalError("You MUST override EntryField's 'text' variable in your subclass.") }
|
||||
}
|
||||
|
||||
|
||||
open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var transparentBackground: Bool = false { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var width: CGFloat? { didSet { setNeedsUpdate() } }
|
||||
|
||||
open var maxLength: Int? { didSet { setNeedsUpdate() } }
|
||||
|
||||
|
||||
open var inputId: String? { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// The text of this textField.
|
||||
private var _value: String?
|
||||
internal var _value: String?
|
||||
open var value: String? {
|
||||
get { _value }
|
||||
set {
|
||||
if let newValue, newValue != _value {
|
||||
_value = newValue
|
||||
text = newValue
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +300,6 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
tooltipModel = nil
|
||||
transparentBackground = false
|
||||
width = nil
|
||||
maxLength = nil
|
||||
inputId = nil
|
||||
value = nil
|
||||
defaultValue = nil
|
||||
@ -335,7 +326,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable {
|
||||
//--------------------------------------------------
|
||||
private func updateContainerView() {
|
||||
containerView.backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||
containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor
|
||||
containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor
|
||||
containerView.layer.borderWidth = VDSFormControls.widthBorder
|
||||
containerView.layer.cornerRadius = VDSFormControls.borderradius
|
||||
}
|
||||
|
||||
@ -78,17 +78,28 @@ open class InputField: EntryFieldBase, UITextFieldDelegate {
|
||||
/// Representing the type of input.
|
||||
open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// The text of this textField.
|
||||
open override var text: String? {
|
||||
get { textField.text }
|
||||
/// The text of this TextField.
|
||||
private var _text: String?
|
||||
open var text: String? {
|
||||
get { _text }
|
||||
set {
|
||||
if let newValue, newValue != text {
|
||||
if let newValue, newValue != _text {
|
||||
_text = newValue
|
||||
textField.text = newValue
|
||||
value = newValue
|
||||
}
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// The value of this textField.
|
||||
open override var value: String? {
|
||||
didSet {
|
||||
if text != value {
|
||||
text = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _showError: Bool = false
|
||||
/// Whether not to show the error.
|
||||
|
||||
@ -105,11 +105,11 @@ open class TextArea: EntryFieldBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The text of this textView
|
||||
|
||||
/// The text of this TextArea.
|
||||
private var _text: String?
|
||||
open override var text: String? {
|
||||
get { textView.text }
|
||||
open var text: String? {
|
||||
get { _text }
|
||||
set {
|
||||
if let newValue, newValue != _text {
|
||||
_text = newValue
|
||||
@ -119,6 +119,15 @@ open class TextArea: EntryFieldBase {
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// The value of this textField.
|
||||
open override var value: String? {
|
||||
didSet {
|
||||
if text != value {
|
||||
text = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// UITextView shown in the TextArea.
|
||||
open var textView = TextView().with {
|
||||
@ -127,7 +136,15 @@ open class TextArea: EntryFieldBase {
|
||||
$0.isScrollEnabled = false
|
||||
}
|
||||
|
||||
open override var maxLength: Int? { willSet { countRule.maxLength = newValue }}
|
||||
open var maxLength: Int? {
|
||||
willSet {
|
||||
countRule.maxLength = newValue
|
||||
}
|
||||
|
||||
didSet {
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// Color configuration for error icon.
|
||||
internal var iconColorConfiguration = ControlColorConfiguration().with {
|
||||
|
||||
@ -29,6 +29,7 @@ Using the system allows designers and developers to collaborate more easily and
|
||||
- ``Checkbox``
|
||||
- ``CheckboxItem``
|
||||
- ``CheckboxGroup``
|
||||
- ``DropdownSelect``
|
||||
- ``Icon``
|
||||
- ``InputField``
|
||||
- ``Label``
|
||||
|
||||
Loading…
Reference in New Issue
Block a user