Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98dde01e18 | |||
| 78dd2d5df8 | |||
| 58850aeb6e | |||
|
|
15a53964c5 | ||
|
|
762868609b | ||
|
|
e256dfd209 | ||
|
|
a1236df9a9 | ||
|
|
539f10ffbf | ||
|
|
cc530e5903 | ||
|
|
482212e88c | ||
|
|
47409d2905 | ||
|
|
16516fbeed | ||
|
|
484d12626e | ||
|
|
9856c0a482 | ||
|
|
4797e5a7f7 | ||
|
|
942834ec3e | ||
|
|
62aedc7c5a | ||
|
|
2e3524cde6 | ||
|
|
735749eaa5 | ||
|
|
4e581491fa | ||
|
|
4fbbe485f7 | ||
|
|
216971b878 | ||
|
|
d66d4d0e26 | ||
|
|
c352fbaac9 | ||
|
|
759ef0db5b | ||
|
|
dc7dbffcf6 | ||
|
|
a019c1ba36 | ||
|
|
fc6b2991b8 | ||
|
|
dd437d7423 | ||
|
|
025700a632 | ||
|
|
50117f3f2f | ||
|
|
8057b16e5b | ||
|
|
1728592bff |
@ -23,6 +23,8 @@
|
||||
1842B1E12BECE7B70021AFCA /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E02BECE7B70021AFCA /* CalendarHeaderReusableView.swift */; };
|
||||
1842B1E32BECF0A20021AFCA /* CalendarFooterReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */; };
|
||||
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; };
|
||||
1859B30F2CBF6FEB0031CD70 /* ListUnordered.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */; };
|
||||
1859B31B2CBFA0180031CD70 /* ListUnorderedItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */; };
|
||||
186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; };
|
||||
18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; };
|
||||
18926F5B2C7616A500C55BF6 /* FootnoteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */; };
|
||||
@ -241,6 +243,9 @@
|
||||
1842B1E22BECF0A10021AFCA /* CalendarFooterReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarFooterReusableView.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListUnordered.swift; sourceTree = "<group>"; };
|
||||
1859B3122CBF70AB0031CD70 /* ListUnordered.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ListUnordered.txt; sourceTree = "<group>"; };
|
||||
1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListUnorderedItemModel.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>"; };
|
||||
@ -508,6 +513,16 @@
|
||||
path = PriceLockup;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1859B30D2CBF6EF80031CD70 /* ListUnordered */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1859B30E2CBF6FDD0031CD70 /* ListUnordered.swift */,
|
||||
1859B31A2CBFA0180031CD70 /* ListUnorderedItemModel.swift */,
|
||||
1859B3122CBF70AB0031CD70 /* ListUnordered.txt */,
|
||||
);
|
||||
path = ListUnordered;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
186D13C92BBA8A3500986B53 /* DropdownSelect */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -759,6 +774,7 @@
|
||||
180636C52C29B06200C92D86 /* InputStepper */,
|
||||
EA3362412892EF700071C351 /* Label */,
|
||||
44604AD529CE195300E62B51 /* Line */,
|
||||
1859B30D2CBF6EF80031CD70 /* ListUnordered */,
|
||||
EAD0688C2A55F801002E3A2D /* Loader */,
|
||||
18C0F9442C980CE500E1DD71 /* Modal */,
|
||||
445BA07629C07ABA0036A7C5 /* Notification */,
|
||||
@ -1347,6 +1363,7 @@
|
||||
EA6642952BCEBF9500D81DC4 /* TextLinkModel.swift in Sources */,
|
||||
71FC86E22B97483000700965 /* Clamping.swift in Sources */,
|
||||
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
|
||||
1859B30F2CBF6FEB0031CD70 /* ListUnordered.swift in Sources */,
|
||||
1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */,
|
||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
|
||||
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
||||
@ -1414,6 +1431,7 @@
|
||||
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */,
|
||||
18B42AC62C09D197008D6262 /* CarouselSlotAlignmentModel.swift in Sources */,
|
||||
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */,
|
||||
1859B31B2CBFA0180031CD70 /* ListUnorderedItemModel.swift in Sources */,
|
||||
EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */,
|
||||
EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */,
|
||||
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
|
||||
@ -1653,7 +1671,7 @@
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 74;
|
||||
CURRENT_PROJECT_VERSION = 75;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@ -1691,7 +1709,7 @@
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 74;
|
||||
CURRENT_PROJECT_VERSION = 75;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
|
||||
/// Base Class use to build Controls.
|
||||
@objcMembers
|
||||
@objc(VDSControl)
|
||||
open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -28,7 +28,6 @@ public protocol SelectorControlable: Control, Changeable {
|
||||
}
|
||||
|
||||
/// Base Class used to build out a Selector control.
|
||||
@objcMembers
|
||||
@objc(VDSSelectorBase)
|
||||
open class SelectorBase: Control, SelectorControlable, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
|
||||
/// Base Class used to build Views.
|
||||
@objcMembers
|
||||
@objc(VDSView)
|
||||
open class View: UIView, ViewProtocol, UserInfoable, Clickable {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSAlertViewController)
|
||||
open class AlertViewController: UIViewController, Surfaceable {
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSClearPopoverViewController)
|
||||
open class ClearPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate {
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ import Combine
|
||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||
/// to its parent this object will stretch to the parent's width.
|
||||
@objcMembers
|
||||
@objc(VDSBadge)
|
||||
open class Badge: View, ParentViewProtocol {
|
||||
|
||||
@ -38,8 +37,16 @@ open class Badge: View, ParentViewProtocol {
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
/// Enum used to describe the primary color for the view.
|
||||
public enum FillColor: String, CaseIterable {
|
||||
public enum FillColor: Equatable {
|
||||
case red, yellow, green, orange, blue, black, white
|
||||
case token(UIColor.VDSColor)
|
||||
case custom(UIColor)
|
||||
|
||||
private var reflectedValue: String { String(reflecting: self) }
|
||||
|
||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.reflectedValue == rhs.reflectedValue
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -65,6 +72,8 @@ open class Badge: View, ParentViewProtocol {
|
||||
/// The text that will be shown in the label.
|
||||
open var text: String = "" { didSet { setNeedsUpdate() }}
|
||||
|
||||
open var textColor: TextColor? { didSet { setNeedsUpdate() }}
|
||||
|
||||
/// When applied, this property takes a px value that will restrict the width at that point.
|
||||
open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }}
|
||||
|
||||
@ -93,38 +102,91 @@ open class Badge: View, ParentViewProtocol {
|
||||
right: VDSLayout.space1X)
|
||||
|
||||
/// ColorConfiguration that is mapped to the 'fillColor' for the surface.
|
||||
private var backgroundColorConfiguration: AnyColorable = {
|
||||
let config = KeyedColorConfiguration<Badge, FillColor>(keyPath: \.fillColor)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundRedOnlight, VDSColor.badgesBackgroundRedOndark, forKey: .red)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundYellowOnlight, VDSColor.badgesBackgroundYellowOndark, forKey: .yellow)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundGreenOnlight, VDSColor.badgesBackgroundGreenOndark, forKey: .green)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundOrangeOnlight, VDSColor.badgesBackgroundOrangeOndark, forKey: .orange)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundBlueOnlight, VDSColor.badgesBackgroundBlueOndark, forKey: .blue)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundBlackOnlight, VDSColor.badgesBackgroundBlackOndark, forKey: .black)
|
||||
config.setSurfaceColors(VDSColor.badgesBackgroundWhiteOnlight, VDSColor.badgesBackgroundWhiteOndark, forKey: .white)
|
||||
return config.eraseToAnyColorable()
|
||||
}()
|
||||
private var backgroundColorConfiguration = SurfaceColorConfiguration()
|
||||
|
||||
/// ColorConfiguration for the Text.
|
||||
private var textColorConfiguration = ViewColorConfiguration()
|
||||
|
||||
/// Updates the textColorConfiguration based on the fillColor.
|
||||
public func updateTextColorConfig() {
|
||||
public func updateColorConfig() {
|
||||
var config = backgroundColorConfiguration
|
||||
switch fillColor {
|
||||
case .red:
|
||||
config.lightColor = VDSColor.badgesBackgroundRedOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundRedOndark
|
||||
case .yellow:
|
||||
config.lightColor = VDSColor.badgesBackgroundYellowOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundYellowOndark
|
||||
case .green:
|
||||
config.lightColor = VDSColor.badgesBackgroundGreenOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundGreenOndark
|
||||
case .orange:
|
||||
config.lightColor = VDSColor.badgesBackgroundOrangeOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundOrangeOndark
|
||||
case .blue:
|
||||
config.lightColor = VDSColor.badgesBackgroundBlueOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundBlueOndark
|
||||
case .black:
|
||||
config.lightColor = VDSColor.badgesBackgroundBlackOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundBlackOndark
|
||||
case .white:
|
||||
config.lightColor = VDSColor.badgesBackgroundWhiteOnlight
|
||||
config.darkColor = VDSColor.badgesBackgroundWhiteOndark
|
||||
case .token(let color):
|
||||
config.lightColor = color.uiColor
|
||||
config.darkColor = color.uiColor
|
||||
case .custom(let color):
|
||||
config.lightColor = color
|
||||
config.darkColor = color
|
||||
}
|
||||
|
||||
textColorConfiguration.reset()
|
||||
|
||||
switch fillColor {
|
||||
func update(for color: UIColor) {
|
||||
if let configuration = textColor?.configuration {
|
||||
textColorConfiguration = configuration
|
||||
} else {
|
||||
if color.isDark() {
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
||||
} else {
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||
|
||||
case .red, .black:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case .yellow, .white:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||
if let textColor {
|
||||
switch textColor {
|
||||
case .token(let color):
|
||||
textColorConfiguration.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: true)
|
||||
case .custom(let color):
|
||||
textColorConfiguration.setSurfaceColors(color, color, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(color, color, forDisabled: true)
|
||||
}
|
||||
} else {
|
||||
switch fillColor {
|
||||
|
||||
case .orange, .green, .blue:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||
case .red, .black:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true)
|
||||
|
||||
case .yellow, .white:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||
|
||||
case .orange, .green, .blue:
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false)
|
||||
textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true)
|
||||
|
||||
case .token(let color):
|
||||
update(for: color.uiColor)
|
||||
|
||||
case .custom(let color):
|
||||
update(for: color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +241,7 @@ open class Badge: View, ParentViewProtocol {
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
updateTextColorConfig()
|
||||
updateColorConfig()
|
||||
updateMaxWidth()
|
||||
|
||||
backgroundColor = backgroundColorConfiguration.getColor(self)
|
||||
@ -191,3 +253,29 @@ open class Badge: View, ParentViewProtocol {
|
||||
label.isEnabled = isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
extension Badge{
|
||||
public enum TextColor: Equatable {
|
||||
case token(UIColor.VDSColor)
|
||||
case custom(UIColor)
|
||||
|
||||
private var reflectedValue: String { String(reflecting: self) }
|
||||
|
||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.reflectedValue == rhs.reflectedValue
|
||||
}
|
||||
|
||||
public var configuration: ViewColorConfiguration {
|
||||
let config = ViewColorConfiguration()
|
||||
switch self {
|
||||
case .token(let color):
|
||||
config.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: true)
|
||||
config.setSurfaceColors(color.uiColor, color.uiColor, forDisabled: false)
|
||||
case .custom(let color):
|
||||
config.setSurfaceColors(color, color, forDisabled: true)
|
||||
config.setSurfaceColors(color, color, forDisabled: false)
|
||||
}
|
||||
return config
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A badge indicator is a visual label used to convey status or highlight supplemental information.
|
||||
@objcMembers
|
||||
@objc(VDSBadgeIndicator)
|
||||
open class BadgeIndicator: View, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import Combine
|
||||
/// A Breadcrumb Item contains href(link) and selected flag.
|
||||
/// Breadcrumb links to its respective page if it is not disabled.
|
||||
/// Breadcrumb contains text with a separator by default, highlights text in bold without a separator if selected.
|
||||
@objcMembers
|
||||
@objc (VDSBreadcrumbItem)
|
||||
open class BreadcrumbItem: ButtonBase {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import Combine
|
||||
/// A Breadcrumbs contains BreadcrumbItems.
|
||||
/// It contains Breadcrumb Item Default, Breadcrumb Item Selected, Separator.
|
||||
/// Breadcrumbs are secondary navigation that use a hierarchy of internal links to tell customers where they are in an experience. Each breadcrumb links to its respective page, except for that of current page.
|
||||
@objcMembers
|
||||
@objc(VDSBreadcrumbs)
|
||||
open class Breadcrumbs: View, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ import Combine
|
||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||
/// to its parent this object will stretch to the parent's width.
|
||||
@objcMembers
|
||||
@objc(VDSButton)
|
||||
open class Button: ButtonBase, Useable {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// Base class used for UIButton type classes.
|
||||
@objcMembers
|
||||
@objc(VDSButtonBase)
|
||||
open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A button group contains combinations of related CTAs including ``Button``, ``TextLink``, and ``TextLinkCaret``. This group component controls a combination's orientation, spacing, size and allowable size pairings.
|
||||
@objcMembers
|
||||
@objc(VDSButtonGroup)
|
||||
open class ButtonGroup: View {
|
||||
|
||||
|
||||
@ -16,7 +16,6 @@ import Combine
|
||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||
/// to its parent this object will stretch to the parent's width.
|
||||
@objcMembers
|
||||
@objc(VDSTextLink)
|
||||
open class TextLink: ButtonBase {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -16,7 +16,6 @@ import Combine
|
||||
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
|
||||
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
|
||||
/// to its parent this object will stretch to the parent's width.
|
||||
@objcMembers
|
||||
@objc(VDSTextLinkCaret)
|
||||
open class TextLinkCaret: ButtonBase {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A calendar is a monthly view that lets customers select a single date.
|
||||
@objcMembers
|
||||
@objc(VDSCalendar)
|
||||
open class CalendarBase: Control, Changeable {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A carousel is a collection of related content in a row that a customer can navigate through horizontally.
|
||||
/// Use this component to show content that is supplementary, not essential for task completion.
|
||||
@objcMembers
|
||||
@objc(VDSCarousel)
|
||||
open class Carousel: View {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A carousel scrollbar is a control that allows to navigate between items in a carousel.
|
||||
/// It's also a status indicator that conveys the relative amount of content in a carousel and a location within it.
|
||||
@objcMembers
|
||||
@objc(VDSCarouselScrollbar)
|
||||
open class CarouselScrollbar: View {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import VDSCoreTokens
|
||||
|
||||
/// Checkboxes are a multi-select component through which a customer indicates a choice. This is also used within
|
||||
/// ``CheckboxItem`` and ``CheckboxGroup``
|
||||
@objcMembers
|
||||
@objc(VDSCheckbox)
|
||||
open class Checkbox: SelectorBase {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import VDSCoreTokens
|
||||
/// When the choice has multiple options, use a checkbox group. For example, use a checkbox group when
|
||||
/// asking a customer which attributes they would like to filter their search by. This uses ``CheckboxItem``
|
||||
/// to allow user selection.
|
||||
@objcMembers
|
||||
@objc(VDSCheckboxGroup)
|
||||
open class CheckboxGroup: SelectorGroupBase<CheckboxItem>, SelectorGroupMultiSelect {
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import Foundation
|
||||
import UIKit
|
||||
|
||||
/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``.
|
||||
@objcMembers
|
||||
@objc(VDSCheckboxItem)
|
||||
open class CheckboxItem: SelectorItemBase<Checkbox> {
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
||||
@objcMembers
|
||||
@objc(VDSDatePicker)
|
||||
open class DatePicker: EntryFieldBase<String> {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection.
|
||||
@objcMembers
|
||||
@objc(VDSDropdownSelect)
|
||||
open class DropdownSelect: EntryFieldBase<String> {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
/// This must always be paired with one or more ``Footnote`` in a FootnoteGroup.
|
||||
@objcMembers
|
||||
@objc(VDSFootnoteGroup)
|
||||
open class FootnoteGroup: View {
|
||||
|
||||
@ -112,6 +111,12 @@ open class FootnoteGroup: View {
|
||||
footnoteItems = []
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
updateFootnoteItems()
|
||||
}
|
||||
|
||||
internal func updateFootnoteItems() {
|
||||
// symbol containers are as wide as the widest symbol container in the group.
|
||||
var symbolMaxWidth = 0.0
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
|
||||
/// A footnote is text that provides supporting details, legal copy and links to related content.
|
||||
/// It exists at the bottom or "foot" of a page or section.
|
||||
@objcMembers
|
||||
@objc(VDSFootnoteItem)
|
||||
open class FootnoteItem: View {
|
||||
|
||||
@ -207,7 +206,7 @@ open class FootnoteItem: View {
|
||||
|
||||
// Update symbolLabel
|
||||
symbolLabel.text = symbolType
|
||||
symbolLabel.isHidden = hideSymbol
|
||||
symbolLabel.isHidden = symbolType.isEmpty ? true : hideSymbol
|
||||
symbolLabel.textColor = kind.colorConfiguration.getColor(self)
|
||||
symbolLabel.textStyle = size.textStyle.regular
|
||||
symbolLabel.surface = surface
|
||||
|
||||
@ -13,7 +13,6 @@ import Combine
|
||||
/// An icon is a graphical element that conveys information at a glance. It helps orient
|
||||
/// a customer, explain functionality and draw attention to interactive elements. Icons
|
||||
/// should have a functional purpose and should never be used for decoration.
|
||||
@objcMembers
|
||||
@objc(VDSIcon)
|
||||
open class Icon: View {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
/// A stepper is a two-segment control that people use to increase or decrease an incremental value.'
|
||||
@objcMembers
|
||||
@objc(VDSInputStepper)
|
||||
open class InputStepper: EntryFieldBase<Int> {
|
||||
|
||||
|
||||
@ -39,6 +39,27 @@ public extension String {
|
||||
func isValid(range: NSRange) -> Bool {
|
||||
range.location >= 0 && range.length > 0 && range.location + range.length <= count
|
||||
}
|
||||
|
||||
func index(from: Int) -> Index {
|
||||
return self.index(startIndex, offsetBy: from)
|
||||
}
|
||||
|
||||
func substring(from: Int) -> String {
|
||||
let fromIndex = index(from: from)
|
||||
return String(self[fromIndex...])
|
||||
}
|
||||
|
||||
func substring(to: Int) -> String {
|
||||
let toIndex = index(from: to)
|
||||
return String(self[..<toIndex])
|
||||
}
|
||||
|
||||
func substring(with r: Range<Int>) -> String {
|
||||
let startIndex = index(from: r.lowerBound)
|
||||
let endIndex = index(from: r.upperBound)
|
||||
return String(self[startIndex..<endIndex])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension NSAttributedString {
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// Label is a standard view used to draw text with applying Typography through ``TextStyle`` as well
|
||||
/// as other attributes using any implemetation of ``LabelAttributeModel``.
|
||||
@objcMembers
|
||||
@objc(VDSLabel)
|
||||
open class Label: UILabel, ViewProtocol, UserInfoable {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
/// A line visually separates content sections or elements in lists, tables and layouts to indicate content hierarchy.
|
||||
@objcMembers
|
||||
@objc(VDSLine)
|
||||
open class Line: View {
|
||||
|
||||
|
||||
239
VDS/Components/ListUnordered/ListUnordered.swift
Normal file
239
VDS/Components/ListUnordered/ListUnordered.swift
Normal file
@ -0,0 +1,239 @@
|
||||
//
|
||||
// ListUnordered.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Vasavi Kanamarlapudi on 16/10/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
/// List unordered breaks up related content into distinct phrases or sentences, which improves scannability.
|
||||
/// This component should be used when the text items don’t need to be in numeric order.
|
||||
@objcMembers
|
||||
@objc(VDSListUnordered)
|
||||
open class ListUnordered: View {
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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: - Enums
|
||||
//--------------------------------------------------
|
||||
/// Enum that represents the size availble for the component.
|
||||
public enum Size: String, DefaultValuing, CaseIterable {
|
||||
case large
|
||||
case medium
|
||||
case small
|
||||
case micro
|
||||
|
||||
public static var defaultValue: Self { .large }
|
||||
|
||||
/// TextStyle relative to Size.
|
||||
public var textStyle: TextStyle.StandardStyle {
|
||||
switch self {
|
||||
case .large:
|
||||
return .bodyLarge
|
||||
case .medium:
|
||||
return .bodyMedium
|
||||
case .small:
|
||||
return .bodySmall
|
||||
case .micro:
|
||||
return .micro
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum that represents the type of spacing available for the component.
|
||||
public enum Spacing: String, CaseIterable {
|
||||
case standard, compact
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
/// Size of the component. The default size is Large.
|
||||
open var size: Size = .defaultValue { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Spacing type of the component.
|
||||
open var spacing: Spacing = .standard { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Lead-in text that shows as the top text for the component. This is optional.
|
||||
open var leadInText: String? = nil { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Array of unordered list items to show for the component.
|
||||
open var unorderedList: [ListUnorderedItemModel] = [] { didSet { setNeedsUpdate() }}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration Properties
|
||||
//--------------------------------------------------
|
||||
// It can be used for Glyph level 1.
|
||||
private var disc = "•"
|
||||
|
||||
// It can be used for Glyph Level 2.
|
||||
private var endash = "–"
|
||||
|
||||
// Spacing between the list items.
|
||||
private var spaceBetweenItems: CGFloat {
|
||||
switch (size, spacing) {
|
||||
case (.large, .standard):
|
||||
return VDSLayout.space4X
|
||||
case (.medium, .standard), (.small, .standard), (.micro, .standard):
|
||||
return VDSLayout.space3X
|
||||
case (.large, .compact):
|
||||
return VDSLayout.space2X
|
||||
case (.medium, .compact), (.small, .compact), (.micro, .compact):
|
||||
return VDSLayout.space1X
|
||||
}
|
||||
}
|
||||
|
||||
// Padding that can be used in an item between the glyph and the item text.
|
||||
private var padding: CGFloat {
|
||||
switch (size, spacing) {
|
||||
case (.large, .standard), (.large, .compact):
|
||||
return VDSLayout.space3X
|
||||
case (.medium, .standard), (.small, .standard), (.micro, .standard), (.medium, .compact), (.small, .compact), (.micro, .compact):
|
||||
return VDSLayout.space2X
|
||||
}
|
||||
}
|
||||
|
||||
private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private lazy var listStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .vertical
|
||||
$0.distribution = .fill
|
||||
$0.spacing = spaceBetweenItems
|
||||
$0.backgroundColor = .clear
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
/// Called once when a view is initialized and is used to Setup additional UI or other constants and config.texturations.
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
// add stackview
|
||||
addSubview(listStackView)
|
||||
listStackView.heightGreaterThanEqualTo(constant:0)
|
||||
listStackView.pinToSuperView()
|
||||
}
|
||||
|
||||
open override func setDefaults() {
|
||||
super.setDefaults()
|
||||
leadInText = nil
|
||||
unorderedList = []
|
||||
}
|
||||
|
||||
/// Resets to default settings.
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
}
|
||||
|
||||
/// Used to make changes to the View based off a change events or from local properties.
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
listStackView.removeArrangedSubviews()
|
||||
listStackView.subviews.forEach { $0.removeFromSuperview() }
|
||||
listStackView.spacing = spaceBetweenItems
|
||||
|
||||
if leadInText != nil {
|
||||
let listItem = getListItem(with:self.leadInText, surface: surface)
|
||||
listStackView.addArrangedSubview(listItem)
|
||||
}
|
||||
|
||||
unorderedList.forEach { item in
|
||||
let listItem = getListItem(levelOneText: item.levelOneText, surface: surface)
|
||||
listStackView.addArrangedSubview(listItem)
|
||||
|
||||
item.levelTwoText?.forEach { text in
|
||||
let listItem = getListItem(levelTwoText: text, surface: surface)
|
||||
listStackView.addArrangedSubview(listItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Methods
|
||||
//--------------------------------------------------
|
||||
// Get Label with the required text and text formats.
|
||||
func getLabel(with text: String?, surface: Surface) -> Label {
|
||||
let textLabel = Label().with {
|
||||
$0.isAccessibilityElement = true
|
||||
$0.lineBreakMode = .byWordWrapping
|
||||
$0.text = text
|
||||
$0.textStyle = size.textStyle.regular
|
||||
$0.textColor = textColorConfiguration.getColor(surface)
|
||||
$0.surface = surface
|
||||
}
|
||||
return textLabel
|
||||
}
|
||||
|
||||
// Get the list item with the required text (LeadInText, Level 1 Text, Level 2 Text).
|
||||
func getListItem(with leadInText:String? = nil, levelOneText: String? = nil, levelTwoText: String? = nil, surface:Surface) -> UIView {
|
||||
let itemStackView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.axis = .horizontal
|
||||
$0.alignment = .leading
|
||||
$0.distribution = .fill
|
||||
$0.spacing = padding
|
||||
$0.backgroundColor = .clear
|
||||
}
|
||||
|
||||
// StackView with LeadIntext if provided.
|
||||
if leadInText != nil {
|
||||
let leadTextLabel = getLabel(with: leadInText, surface: surface)
|
||||
itemStackView.addArrangedSubview(leadTextLabel)
|
||||
}
|
||||
|
||||
// StackView with Level 1 Text if provided.
|
||||
if levelOneText != nil {
|
||||
|
||||
// Add level 1 glyph: 'disc, bold'
|
||||
let discLabel = getLabel(with: disc, surface: surface)
|
||||
discLabel.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
|
||||
itemStackView.addArrangedSubview(discLabel)
|
||||
|
||||
// Add level 1 Text
|
||||
let levelOneLabel = getLabel(with: levelOneText, surface: surface)
|
||||
itemStackView.addArrangedSubview(levelOneLabel)
|
||||
}
|
||||
|
||||
// StackView with Level 2 Text if provided.
|
||||
if levelTwoText != nil {
|
||||
|
||||
// Set level 2 leading space as needed for alignment.
|
||||
let discSpaceView = View()
|
||||
let discLabel = getLabel(with: disc, surface: surface)
|
||||
discSpaceView.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
|
||||
itemStackView.addArrangedSubview(discSpaceView)
|
||||
|
||||
// Add level 2 glyph: 'en dash, regular'
|
||||
let endashLabel = getLabel(with: endash, surface: surface)
|
||||
endashLabel.widthAnchor.constraint(equalToConstant: endashLabel.intrinsicContentSize.width).activate()
|
||||
itemStackView.addArrangedSubview(endashLabel)
|
||||
|
||||
// Add level 2 Text
|
||||
let levelTwoLabel = getLabel(with: levelTwoText, surface: surface)
|
||||
itemStackView.addArrangedSubview(levelTwoLabel)
|
||||
}
|
||||
return itemStackView
|
||||
}
|
||||
}
|
||||
41
VDS/Components/ListUnordered/ListUnordered.txt
Normal file
41
VDS/Components/ListUnordered/ListUnordered.txt
Normal file
@ -0,0 +1,41 @@
|
||||
MM/DD/YYYY
|
||||
----------------
|
||||
- Initial Brand 3.0 handoff
|
||||
|
||||
05/2/2022
|
||||
----------------
|
||||
- Added Body Medium to size configuration
|
||||
|
||||
05/5/2022
|
||||
----------------
|
||||
- Added Spacing configuration (Standard, Compact) Web handoff
|
||||
|
||||
08/2/2022
|
||||
----------------
|
||||
- Included a VDS Note about the Spacing prop naming rationale
|
||||
|
||||
08/10/2022
|
||||
----------------
|
||||
- Updated default and inverted prop to light and dark surface.
|
||||
|
||||
12/13/2022
|
||||
----------------
|
||||
- Replaced focus border pixel and style & spacing values with tokens.
|
||||
|
||||
01/10/2023
|
||||
----------------
|
||||
- Removed from Anatomy section: “List item text”
|
||||
- Updated “Glyph level 1” to “List Item Level 1”
|
||||
- Updated “Glyph level 2” to “List Item Level 2”
|
||||
- Updated image markers to reflect changes
|
||||
|
||||
02/02/2023
|
||||
----------------
|
||||
- Reduced left padding for all Level 2 sizes so that the Glyph aligns with the text in Level 1.
|
||||
- Added dashed line on all sizes to indicate Level 2 alignment under Level 1.
|
||||
- Changed “endash” to “endash, regular” under Size section.
|
||||
- Updated all Level 1 and Level 2 glyph widths to “Hug”
|
||||
|
||||
12/26/23
|
||||
----------------
|
||||
- Deleted Decisions log
|
||||
23
VDS/Components/ListUnordered/ListUnorderedItemModel.swift
Normal file
23
VDS/Components/ListUnordered/ListUnorderedItemModel.swift
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// ListUnorderedItemModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Vasavi Kanamarlapudi on 16/10/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
extension ListUnordered {
|
||||
public struct ListUnorderedItemModel: Equatable {
|
||||
|
||||
/// Item Level 1 that shows text with glyph - disc, bold.
|
||||
public var levelOneText: String
|
||||
|
||||
/// Item Level 2 that shows text (one or many) with glyph - en dash. This is optional.
|
||||
public var levelTwoText: [String?]?
|
||||
|
||||
public init(itemLevelOneText: String, itemLevelTwoTexts: [String?]? = nil) {
|
||||
self.levelOneText = itemLevelOneText
|
||||
self.levelTwoText = itemLevelTwoTexts
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
|
||||
|
||||
/// A loader is an indicator that uses animation to show customers that there is an indefinite amount of wait time while a task is ongoing, e.g. a page is loading, a form is being submitted. The component disappears when the task is complete.
|
||||
@objcMembers
|
||||
@objc(VDSLoader)
|
||||
open class Loader: View {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
/// ViewController to show the Loader, this will be presented using the LoaderLaunchable Protocl.
|
||||
@objcMembers
|
||||
@objc(VDSLoaderViewController)
|
||||
open class LoaderViewController: UIViewController, Surfaceable {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A Modal is an overlay that interrupts the user flow to force the customer to provide information or a response.
|
||||
/// After the customer interacts with the modal, they can return to the parent content.
|
||||
@objcMembers
|
||||
@objc(VDSModal)
|
||||
open class Modal: Control, ModalLaunchable {
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import Foundation
|
||||
import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSModalDialog)
|
||||
open class ModalDialog: View, UIScrollViewDelegate, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSModalDialogViewController)
|
||||
open class ModalDialogViewController: UIViewController, Surfaceable {
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@ import Combine
|
||||
/// in context. There are four types: information, success, warning and error; each
|
||||
/// with different color and content. They may be screen-specific, flow-specific or
|
||||
/// experience-wide.
|
||||
@objcMembers
|
||||
@objc(VDSNotification)
|
||||
open class Notification: View, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages.
|
||||
@objcMembers
|
||||
@objc(VDSPagination)
|
||||
open class Pagination: View {
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
///This is customised button for Pagination view
|
||||
@objcMembers
|
||||
@objc(PaginationButton)
|
||||
open class PaginationButton: ButtonBase {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -9,7 +9,6 @@ import Foundation
|
||||
import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSPriceLockup)
|
||||
open class PriceLockup: View, ParentViewProtocol {
|
||||
|
||||
@ -140,6 +139,7 @@ open class PriceLockup: View, ParentViewProtocol {
|
||||
internal var delimiterIndex = 0
|
||||
internal var strikethroughLocation = 0
|
||||
internal var strikethroughLength = 0
|
||||
internal var strikethroughAccessibilityText: String = "price not offering anymore"
|
||||
|
||||
internal var textPosition:TextPosition = .preDelimiter
|
||||
enum TextPosition: String, CaseIterable {
|
||||
@ -217,6 +217,24 @@ open class PriceLockup: View, ParentViewProtocol {
|
||||
|
||||
open override func setDefaults() {
|
||||
super.setDefaults()
|
||||
|
||||
priceLockupLabel.bridge_accessibilityLabelBlock = { [weak self] in
|
||||
guard let self else { return "" }
|
||||
var accessibilityLabels = [String]()
|
||||
if let text = priceLockupLabel.text, !text.isEmpty {
|
||||
if strikethrough, strikethroughLength > 0 {
|
||||
let preText = text.substring(to: strikethroughLocation)
|
||||
let postText = text.substring(from: strikethroughLocation)
|
||||
accessibilityLabels.append(preText)
|
||||
accessibilityLabels.append(strikethroughAccessibilityText)
|
||||
accessibilityLabels.append(postText)
|
||||
} else {
|
||||
accessibilityLabels.append(text)
|
||||
}
|
||||
}
|
||||
return accessibilityLabels.joined(separator: " ")
|
||||
}
|
||||
|
||||
bold = false
|
||||
hideCurrency = false
|
||||
leadingText = nil
|
||||
|
||||
@ -11,7 +11,6 @@ import UIKit
|
||||
/// Radio boxes are single-select components through which a customer indicates a choice.
|
||||
/// They're stylized ``RadioButtons`` that must always be paired with one or more ``RadioBoxItem``
|
||||
/// in a radio box group. Use radio boxes to display choices like device storage.
|
||||
@objcMembers
|
||||
@objc(VDSRadioBoxGroup)
|
||||
open class RadioBoxGroup: SelectorGroupBase<RadioBoxItem>, SelectorGroupSingleSelect {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import VDSCoreTokens
|
||||
|
||||
/// Radio boxes are single-select components through which a customer indicates a choice
|
||||
/// that are used within a ``RadioBoxGroup``.
|
||||
@objcMembers
|
||||
@objc(VDSRadioBoxItem)
|
||||
open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import VDSCoreTokens
|
||||
/// Radio buttons are single-select components through which a customer indicates a choice.
|
||||
/// They must always be paired with one or more ``RadioButtonItem`` within a ``RadioButtonGroup``.
|
||||
/// Use radio buttons to display choices like delivery method.
|
||||
@objcMembers
|
||||
@objc(VDSRadioButton)
|
||||
open class RadioButton: SelectorBase {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import UIKit
|
||||
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
||||
/// They must always be paired with one or more other ``RadioButtonItem`` within a radio button group.
|
||||
/// Use radio buttons to display choices like delivery method.
|
||||
@objcMembers
|
||||
@objc(VDSRadioButtonGroup)
|
||||
open class RadioButtonGroup: SelectorGroupBase<RadioButtonItem>, SelectorGroupSingleSelect {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import UIKit
|
||||
/// Radio buttons items are single-select components through which a customer indicates a choice.
|
||||
/// They must always be paired with one or more other radio button items within a ``RadioButtonGroup``.
|
||||
/// Use radio buttons to display choices like delivery method.
|
||||
@objcMembers
|
||||
@objc(VDSRadioButtonItem)
|
||||
open class RadioButtonItem: SelectorItemBase<RadioButton> {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
///Table is view composed of rows and columns, which takes any view into each cell and resizes based on the highest cell height.
|
||||
@objcMembers
|
||||
@objc(VDSTable)
|
||||
open class Table: View {
|
||||
|
||||
@ -27,7 +26,6 @@ open class Table: View {
|
||||
$0.allowsSelection = false
|
||||
$0.showsVerticalScrollIndicator = false
|
||||
$0.showsHorizontalScrollIndicator = false
|
||||
$0.isAccessibilityElement = true
|
||||
$0.backgroundColor = .clear
|
||||
}
|
||||
|
||||
@ -148,6 +146,7 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl
|
||||
var edgePadding = UIEdgeInsets(top: padding.verticalValue(), left: 0, bottom: padding.verticalValue(), right: padding.horizontalValue())
|
||||
edgePadding.left = (indexPath.row == 0 && !striped) ? VDSLayout.space1X : padding.horizontalValue()
|
||||
cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: edgePadding, isHeader: isHeader)
|
||||
setAccessibilityForCell(cell: cell, content: currentItem, path: indexPath)
|
||||
return cell
|
||||
}
|
||||
|
||||
@ -162,4 +161,38 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl
|
||||
func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat {
|
||||
return columnWidths?[indexPath.row] ?? 0.0
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessibility
|
||||
//--------------------------------------------------
|
||||
|
||||
/// To set the accessibility label for the each cell based on the criteria. Table name along with total no of column & row information should be passed in the first cell's accessibility label.
|
||||
private func setAccessibilityForCell(cell: TableCellItem, content: TableItemModel, path: IndexPath) {
|
||||
|
||||
var accLabel = content.component?.accessibilityLabel ?? "Empty"
|
||||
|
||||
///Set the type of header label
|
||||
if path.section == 0 {
|
||||
accLabel.append(", Column Header")
|
||||
} else if path.row == 0 {
|
||||
///As per design team, inspite of column 0 may not look like a header, it should be read as header.
|
||||
accLabel.append(", Row Header")
|
||||
}
|
||||
|
||||
///Set the Row/Column number for each cell
|
||||
if path.row == 0 {
|
||||
accLabel.append(", Row \(path.section + 1), Column \(path.row + 1)")
|
||||
} else {
|
||||
accLabel.append(", Column \(path.row + 1)")
|
||||
}
|
||||
|
||||
///Set the Row header accessibilityLabel at the end of the non-header cells accessibilityLabel
|
||||
if path.section != 0,
|
||||
path.row != 0,
|
||||
let columnHeaderAccLabel = tableHeader.first?.columns[path.row].component?.accessibilityLabel {
|
||||
accLabel.append(", \(columnHeaderAccLabel)")
|
||||
}
|
||||
|
||||
cell.accessibilityLabel = accLabel
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ final class TableCellItem: UICollectionViewCell {
|
||||
|
||||
private func setupCell() {
|
||||
contentView.backgroundColor = .clear
|
||||
isAccessibilityElement = true
|
||||
|
||||
addSubview(containerView)
|
||||
containerView.pinToSuperView()
|
||||
|
||||
@ -11,8 +11,7 @@ import VDSCoreTokens
|
||||
import Combine
|
||||
|
||||
extension Tabs {
|
||||
@objcMembers
|
||||
@objc(VDSTab)
|
||||
@objc(VDSTab)
|
||||
open class Tab: Control, Groupable {
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
/// Tabs are organizational components that group content and allow customers to navigate its display. Use them to separate content when the content is related but doesn’t need to be compared.
|
||||
@objcMembers
|
||||
@objc(VDSTabs)
|
||||
open class Tabs: View, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTabsContainer)
|
||||
open class TabsContainer: View {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import Combine
|
||||
/// An input field is an input wherein a customer enters information. They typically appear in forms.
|
||||
/// Specialized input fields capture credit card numbers, inline actions, passwords, phone numbers,
|
||||
/// dates and security codes in their correct formats.
|
||||
@objcMembers
|
||||
@objc(VDSInputField)
|
||||
open class InputField: EntryFieldBase<String> {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTextField)
|
||||
open class TextField: UITextField, ViewProtocol, Errorable {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A text area is an input wherein a customer enters long-form information.
|
||||
/// Use a text area when you want customers to enter text that’s longer than a single line.
|
||||
@objcMembers
|
||||
@objc(VDSTextArea)
|
||||
open class TextArea: EntryFieldBase<String> {
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTextView)
|
||||
open class TextView: UITextView, ViewProtocol, Errorable {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import VDSCoreTokens
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTileContainer)
|
||||
open class TileContainer: TileContainerBase<TileContainer.Padding> {
|
||||
|
||||
@ -346,8 +345,15 @@ open class TileContainerBase<PaddingType: DefaultValuing & Valuing>: View where
|
||||
containerView.setAccessibilityLabel(for: views)
|
||||
|
||||
//append all children that are accessible
|
||||
items.append(contentsOf: elements)
|
||||
|
||||
if containerView.isAccessibilityElement {
|
||||
elements.forEach({ element in
|
||||
if element.accessibilityTraits.contains(.button) || element.accessibilityTraits.contains(.link) {
|
||||
items.append(element)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
items.append(contentsOf: elements)
|
||||
}
|
||||
return items
|
||||
}
|
||||
set {}
|
||||
|
||||
@ -15,7 +15,6 @@ import Combine
|
||||
/// support quick scanning and engagement. A Tilelet is fully clickable and
|
||||
/// while it can include an arrow CTA, it does not require one in order to
|
||||
/// function.
|
||||
@objcMembers
|
||||
@objc(VDSTilelet)
|
||||
open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
|
||||
@ -104,7 +103,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
}
|
||||
|
||||
private var backgroundColorSurface: Surface {
|
||||
backgroundColorConfiguration.getColor(self).surface
|
||||
backgroundColorConfiguration.getColor(self).isDark() ? .dark : .light
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -280,6 +279,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
internal var iconContainerHeightConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupWidthConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupTrailingConstraint: NSLayoutConstraint?
|
||||
internal var titleLockupTopConstraint: NSLayoutConstraint?
|
||||
@ -328,15 +328,15 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
|
||||
iconContainerView.addSubview(descriptiveIcon)
|
||||
iconContainerView.addSubview(directionalIcon)
|
||||
|
||||
iconContainerHeightConstraint = iconContainerView.height(constant: 0)
|
||||
descriptiveIcon
|
||||
.pinLeading()
|
||||
.pinTop()
|
||||
.pinTopGreaterThanOrEqualTo()
|
||||
.pinBottom()
|
||||
|
||||
directionalIcon
|
||||
.pinTrailing()
|
||||
.pinTop()
|
||||
.pinTopGreaterThanOrEqualTo()
|
||||
.pinBottom()
|
||||
|
||||
badge.bottomAnchor.constraint(equalTo: badge.label.bottomAnchor, constant: 2).activate()
|
||||
@ -468,6 +468,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
private func updateBadge() {
|
||||
if let badgeModel {
|
||||
badge.text = badgeModel.text
|
||||
badge.textColor = badgeModel.textColor
|
||||
badge.fillColor = badgeModel.fillColor
|
||||
badge.numberOfLines = badgeModel.numberOfLines
|
||||
badge.surface = backgroundColorSurface
|
||||
@ -558,6 +559,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
descriptiveIcon.color = color
|
||||
}
|
||||
descriptiveIcon.size = descriptiveIconModel.size
|
||||
iconContainerHeightConstraint?.constant = descriptiveIcon.size.dimensions.height
|
||||
descriptiveIcon.surface = backgroundColorSurface
|
||||
showIconContainerView = true
|
||||
}
|
||||
@ -568,6 +570,7 @@ open class Tilelet: TileContainerBase<Tilelet.Padding>, ParentViewProtocol {
|
||||
directionalIcon.color = color
|
||||
}
|
||||
directionalIcon.size = directionalIconModel.size.value
|
||||
iconContainerHeightConstraint?.constant = directionalIcon.size.dimensions.height
|
||||
directionalIcon.surface = backgroundColorSurface
|
||||
showIconContainerView = true
|
||||
}
|
||||
|
||||
@ -15,6 +15,9 @@ extension Tilelet {
|
||||
/// Text that will be used for the badge.
|
||||
public var text: String = ""
|
||||
|
||||
/// Text color that will be used for the badge.
|
||||
public var textColor: Badge.TextColor?
|
||||
|
||||
/// Fill color that will be used for the badge.
|
||||
public var fillColor: Badge.FillColor
|
||||
|
||||
@ -30,8 +33,9 @@ extension Tilelet {
|
||||
/// LineBreakMode used in Badge label.
|
||||
public var lineBreakMode: NSLineBreakMode
|
||||
|
||||
public init(text: String, fillColor: Badge.FillColor = .red, surface: Surface = .light, numberOfLines: Int = 0, maxWidth: CGFloat? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
|
||||
public init(text: String, textColor: Badge.TextColor? = nil, fillColor: Badge.FillColor = .red, surface: Surface = .light, numberOfLines: Int = 0, maxWidth: CGFloat? = nil, lineBreakMode: NSLineBreakMode = .byTruncatingTail) {
|
||||
self.text = text
|
||||
self.textColor = textColor
|
||||
self.fillColor = fillColor
|
||||
self.surface = surface
|
||||
self.numberOfLines = numberOfLines
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// Title Lockup ensures the readability of words on the screen
|
||||
/// with approved built in text size configurations.
|
||||
@objcMembers
|
||||
@objc(VDSTitleLockup)
|
||||
open class TitleLockup: View, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A toggle is a control that lets customers instantly turn on
|
||||
/// or turn off a single option, setting or function.
|
||||
@objcMembers
|
||||
@objc(VDSToggle)
|
||||
open class Toggle: Control, Changeable, FormFieldable, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import Combine
|
||||
|
||||
/// A toggle is a control that lets customers instantly turn on
|
||||
/// or turn off a single option, setting or function.
|
||||
@objcMembers
|
||||
@objc(VDSToggleView)
|
||||
open class ToggleView: Control, Changeable, FormFieldable {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import Combine
|
||||
/// A tooltip is an overlay that clarifies another component or content
|
||||
/// element. It is triggered when a customer hovers, clicks or taps
|
||||
/// the tooltip icon.
|
||||
@objcMembers
|
||||
@objc(VDSTooltip)
|
||||
open class Tooltip: Control, TooltipLaunchable {
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import UIKit
|
||||
import Combine
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTooltipAlertViewController)
|
||||
open class TooltipAlertViewController: UIViewController, Surfaceable {
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import Foundation
|
||||
import UIKit
|
||||
import VDSCoreTokens
|
||||
|
||||
@objcMembers
|
||||
@objc(VDSTooltipDialog)
|
||||
open class TooltipDialog: View, UIScrollViewDelegate, ParentViewProtocol {
|
||||
|
||||
|
||||
@ -187,10 +187,4 @@ extension UIColor {
|
||||
guard let found else { return nil}
|
||||
return found
|
||||
}
|
||||
|
||||
public var surface: Surface {
|
||||
var greyScale: CGFloat = 0
|
||||
getWhite(&greyScale, alpha: nil)
|
||||
return greyScale < 0.5 ? .dark : .light
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,4 +192,14 @@ extension UIColor {
|
||||
}
|
||||
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
|
||||
}
|
||||
|
||||
internal func isDark() -> Bool {
|
||||
var white: CGFloat = 0
|
||||
var alpha: CGFloat = 0
|
||||
if getWhite(&white, alpha: &alpha) {
|
||||
return white < 0.5
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,16 @@
|
||||
1.0.76
|
||||
----------------
|
||||
- ONEAPP-11355 - ListUnordered - Finished Development
|
||||
- CXTDT-630735 - PriceLockup - Accessibility
|
||||
- CXTDT-626164 - FootnoteGroup - Dark mode
|
||||
- CXTDT-626180 - FootnoteItem - Symbol type padding
|
||||
- CXTDT-586383 - Table - Line style can be selected for each row.
|
||||
|
||||
1.0.75
|
||||
----------------
|
||||
- CXTDT-624895 - Badge - Custom FillColor and TextColor
|
||||
- CXTDT-578885 - Table - Setting appropriate accessiblity label for each cell.
|
||||
|
||||
1.0.74
|
||||
----------------
|
||||
- CXTDT-591307 - DatePicker - Accessibility - #1 & #2
|
||||
|
||||
@ -39,6 +39,7 @@ Using the system allows designers and developers to collaborate more easily and
|
||||
- ``InputField``
|
||||
- ``Label``
|
||||
- ``Line``
|
||||
- ``ListUnordered``
|
||||
- ``Loader``
|
||||
- ``Modal``
|
||||
- ``Notification``
|
||||
|
||||
Loading…
Reference in New Issue
Block a user