diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 6c0e23ad..40fc0d9b 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -36,7 +36,6 @@ EA3361B6288B2A410071C351 /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361B5288B2A410071C351 /* Control.swift */; }; EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */; }; EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361BC288B2C760071C351 /* TypeAlias.swift */; }; - EA3361BF288B2EA60071C351 /* Handlerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361BE288B2EA60071C351 /* Handlerable.swift */; }; EA3361C328902D960071C351 /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361C228902D960071C351 /* Toggle.swift */; }; EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361C8289054C50071C351 /* Surfaceable.swift */; }; EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = EA3362002891E14C0071C351 /* VerizonNHGeTX-Bold.otf */; }; @@ -68,6 +67,8 @@ EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; }; EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBoxItem.swift */; }; EA89201528B56CF4006B9984 /* RadioBoxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */; }; + EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8E40902A7D3F6300934ED3 /* UIView+Accessibility.swift */; }; + EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8E40922A82889500934ED3 /* TooltipDialog.swift */; }; EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */; }; EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BE529688F6A00F2FF2E /* TileletBadgeModel.swift */; }; EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */; }; @@ -99,7 +100,7 @@ EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB2376529E9952D00AABE9A /* UIApplication.swift */; }; EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB2376729E9992800AABE9A /* TooltipAlertViewController.swift */; }; EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB2376929E9E59100AABE9A /* TooltipLaunchable.swift */; }; - EAB5FED429267EB300998C17 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FED329267EB300998C17 /* UIView.swift */; }; + EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FED329267EB300998C17 /* UIView+NSLayoutConstraint.swift */; }; EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */; }; EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */; }; EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; }; @@ -181,7 +182,6 @@ EA3361B5288B2A410071C351 /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewProtocol.swift; sourceTree = ""; }; EA3361BC288B2C760071C351 /* TypeAlias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeAlias.swift; sourceTree = ""; }; - EA3361BE288B2EA60071C351 /* Handlerable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Handlerable.swift; sourceTree = ""; }; EA3361C228902D960071C351 /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; EA3361C8289054C50071C351 /* Surfaceable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Surfaceable.swift; sourceTree = ""; }; EA3362002891E14C0071C351 /* VerizonNHGeTX-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "VerizonNHGeTX-Bold.otf"; sourceTree = ""; }; @@ -213,6 +213,8 @@ EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = ""; }; EA89201228B568D8006B9984 /* RadioBoxItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxItem.swift; sourceTree = ""; }; EA89201428B56CF4006B9984 /* RadioBoxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroup.swift; sourceTree = ""; }; + EA8E40902A7D3F6300934ED3 /* UIView+Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Accessibility.swift"; sourceTree = ""; }; + EA8E40922A82889500934ED3 /* TooltipDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipDialog.swift; sourceTree = ""; }; EA978EC4291D6AFE00ACC883 /* AnyLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyLabelAttribute.swift; sourceTree = ""; }; EA985BE529688F6A00F2FF2E /* TileletBadgeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletBadgeModel.swift; sourceTree = ""; }; EA985BE72968951C00F2FF2E /* TileletTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletTitleModel.swift; sourceTree = ""; }; @@ -245,7 +247,7 @@ EAB2376529E9952D00AABE9A /* UIApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = ""; }; EAB2376729E9992800AABE9A /* TooltipAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipAlertViewController.swift; sourceTree = ""; }; EAB2376929E9E59100AABE9A /* TooltipLaunchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLaunchable.swift; sourceTree = ""; }; - EAB5FED329267EB300998C17 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; + EAB5FED329267EB300998C17 /* UIView+NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+NSLayoutConstraint.swift"; sourceTree = ""; }; EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupPositionLayout.swift; sourceTree = ""; }; EAB5FEF02927F4AA00998C17 /* SelfSizingCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfSizingCollectionView.swift; sourceTree = ""; }; EAB5FEF4292D371F00998C17 /* ButtonBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBase.swift; sourceTree = ""; }; @@ -466,7 +468,8 @@ EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */, EA33623D2892EE950071C351 /* UIDevice.swift */, EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */, - EAB5FED329267EB300998C17 /* UIView.swift */, + EA8E40902A7D3F6300934ED3 /* UIView+Accessibility.swift */, + EAB5FED329267EB300998C17 /* UIView+NSLayoutConstraint.swift */, EAD062A62A3B67770015965D /* UIView+CALayer.swift */, EAB5FF0029424ACB00998C17 /* UIControl.swift */, EA985C662970C21600F2FF2E /* VDSLayout.swift */, @@ -487,7 +490,6 @@ EA5E305929510F8B0082B959 /* EnumSubset.swift */, EAF7F0A1289AFB3900B287F5 /* Errorable.swift */, EA3361AE288B26310071C351 /* FormFieldable.swift */, - EA3361BE288B2EA60071C351 /* Handlerable.swift */, EA33624628931B050071C351 /* Initable.swift */, EA985C7C297DAED300F2FF2E /* Primitive.swift */, EAF7F0A5289B0CE000B287F5 /* Resetable.swift */, @@ -677,6 +679,7 @@ isa = PBXGroup; children = ( EAB2375C29E8789100AABE9A /* Tooltip.swift */, + EA8E40922A82889500934ED3 /* TooltipDialog.swift */, EAB2376729E9992800AABE9A /* TooltipAlertViewController.swift */, EAB2376929E9E59100AABE9A /* TooltipLaunchable.swift */, EAB2376129E9880400AABE9A /* TrailingTooltipLabel.swift */, @@ -954,6 +957,7 @@ EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, + EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */, 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */, EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */, EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */, @@ -965,6 +969,7 @@ EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */, EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */, EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */, + EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */, EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */, EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */, EAD0688E2A55F819002E3A2D /* Loader.swift in Sources */, @@ -995,7 +1000,7 @@ EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */, EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */, EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, - EAB5FED429267EB300998C17 /* UIView.swift in Sources */, + EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */, @@ -1004,7 +1009,6 @@ EAF7F0AD289B142900B287F5 /* StrikeThroughLabelAttribute.swift in Sources */, EAB5FEF12927F4AA00998C17 /* SelfSizingCollectionView.swift in Sources */, EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */, - EA3361BF288B2EA60071C351 /* Handlerable.swift in Sources */, EA3361A8288B23300071C351 /* UIColor.swift in Sources */, EA1DA1CB2A2E36DC001C51D2 /* SelectorBase.swift in Sources */, EAC9257D29119B5400091998 /* TextLink.swift in Sources */, @@ -1163,7 +1167,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 37; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1200,7 +1204,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 37; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/VDS/Classes/ColorConfiguration.swift b/VDS/Classes/ColorConfiguration.swift index a1474610..317a16d3 100644 --- a/VDS/Classes/ColorConfiguration.swift +++ b/VDS/Classes/ColorConfiguration.swift @@ -26,8 +26,8 @@ public typealias ObjectColorable = Colorable & Initable & ObjectWithable /// You can pass in a Surfaceable object and this will return the corresponding Color based on the object's surface property. open class SurfaceColorConfiguration: ObjectColorable { public typealias ObjectType = Surfaceable - public var lightColor: UIColor = .clear - public var darkColor: UIColor = .clear + open var lightColor: UIColor = .clear + open var darkColor: UIColor = .clear required public init(){} @@ -72,11 +72,11 @@ public protocol KeyColorConfigurable: ObjectColorable { extension KeyColorConfigurable { - /// Generic Method to set a KeyColorConfiguration with the parameters given + /// Generic Method to set a KeyColorConfiguration with the parameters given. /// - Parameters: - /// - lightColor: Color used for a light - /// - darkColor: Color used for a dark - /// - key: <#key description#> + /// - lightColor: Color used for a light. + /// - darkColor: Color used for a dark. + /// - key: The key that you want to filter off of. public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forKey key: KeyType) { keyColors.append(.init(key: key, surfaceConfig: .init(lightColor, darkColor))) } diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 6920ac48..10eb8ef9 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -11,17 +11,15 @@ import Combine @objc(VDSControl) /// Base Class use to build Controls. -open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable { +open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- - - /// Set of Subscribers for any Publishers for this Control - public var subscribers = Set() - - /// Sets the primary Subscriber used for the TouchUpInside - public var onClickSubscriber: AnyCancellable? { + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() + + open var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() @@ -37,13 +35,12 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true - /// Dictionary for keeping information for this Control use only Primitives open var userInfo = [String: Primitive]() - /// Current Surface used within this Control and used to passdown to child views + /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() } } - /// Control is disabled or not + /// Whether this object is disabled or not open var disabled: Bool { get { !isEnabled } set { @@ -53,15 +50,14 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab } } - /// Override for isSelected to handle setNeedsUpdate() on changes + /// Whether the Control is selected or not. open override var isSelected: Bool { didSet { setNeedsUpdate() } } - /// Reference count use to be used in isHighlighted when a subscriber is listening for TouchUpInside. - public var touchUpInsideCount: Int = 0 + open var touchUpInsideCount: Int = 0 var isHighlightAnimating = false - /// Override to deal with only calling setNeedsUpdate() if needed + /// Whether the Control is highlighted or not.. open override var isHighlighted: Bool { didSet { if isHighlightAnimating == false && touchUpInsideCount > 0 { @@ -79,7 +75,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab } } - /// Override to deal with setNeedsUpdate() + /// Whether the Control is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } //-------------------------------------------------- @@ -101,10 +97,10 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab } //-------------------------------------------------- - // MARK: - Setup + // MARK: - Lifecycle //-------------------------------------------------- - /// Executed on initialization for this Control + /// Executed on initialization for this Control. open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true @@ -112,26 +108,16 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab setNeedsUpdate() } } - - ///Override to deal with sending actions for accessibility - /// - Returns: Based on whether the userInteraction is enabled - override open func accessibilityActivate() -> Bool { - // Hold state in case User wanted isAnimated to remain off. - guard isUserInteractionEnabled else { return false } - sendActions(for: .touchUpInside) - return true - } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - /// Update this view based off of property changes - open func updateView() { - updateAccessibility() + open func setup() { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + insetsLayoutMarginsFromSafeArea = false } + + /// Function used to make changes to the View based off a change events or from local properties. + open func updateView() { } - /// Used to update any Accessibility properties open func updateAccessibility() { if isSelected { accessibilityTraits.insert(.selected) @@ -146,18 +132,25 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab } } - - /// Resets to the Controls default values + + /// Resets to default settings. open func reset() { backgroundColor = .clear surface = .light disabled = false } - /// Will be called only once and should be overridden in subclasses to setup UI or defaults - open func setup() { - backgroundColor = .clear - translatesAutoresizingMaskIntoConstraints = false - insetsLayoutMarginsFromSafeArea = false + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + + /// Implement accessibilityActivate on an element in order to handle the default action. + /// - Returns: Based on whether the userInteraction is enabled. + override open func accessibilityActivate() -> Bool { + // Hold state in case User wanted isAnimated to remain off. + guard isUserInteractionEnabled else { return false } + sendActions(for: .touchUpInside) + return true } + } diff --git a/VDS/Classes/SelectorBase.swift b/VDS/Classes/SelectorBase.swift index 91935143..cb520876 100644 --- a/VDS/Classes/SelectorBase.swift +++ b/VDS/Classes/SelectorBase.swift @@ -19,16 +19,17 @@ public protocol SelectorControlable: Control, Changeable { } open class SelectorBase: Control, SelectorControlable { - public var onChangeSubscriber: AnyCancellable? { + + open var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { onChangeSubscriber.cancel() } } } - + open var size = CGSize(width: 20, height: 20) { didSet { setNeedsUpdate() }} - + var _showError: Bool = false open var showError: Bool { get { _showError } @@ -51,18 +52,23 @@ open class SelectorBase: Control, SelectorControlable { return state } } - + open var backgroundColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} - + open var borderColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} - - open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} - + + open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() }} + private var selectorView = View() //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- internal var shapeLayer: CAShapeLayer? + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override var intrinsicContentSize: CGSize { size } open override func initialSetup() { super.initialSetup() @@ -70,7 +76,7 @@ open class SelectorBase: Control, SelectorControlable { control.toggle() } } - + open override func setup() { super.setup() @@ -78,10 +84,7 @@ open class SelectorBase: Control, SelectorControlable { accessibilityTraits = .button } - open override var intrinsicContentSize: CGSize { size } - - open func toggle() { } - + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() setNeedsLayout() @@ -91,4 +94,7 @@ open class SelectorBase: Control, SelectorControlable { open override func updateAccessibility() { super.updateAccessibility() } + + open func toggle() { } + } diff --git a/VDS/Classes/SelectorGroupHandlerBase.swift b/VDS/Classes/SelectorGroupHandlerBase.swift index 2575ca2e..868276ba 100644 --- a/VDS/Classes/SelectorGroupHandlerBase.swift +++ b/VDS/Classes/SelectorGroupHandlerBase.swift @@ -9,31 +9,27 @@ import Foundation import UIKit import Combine -/// Base Class used for any Grouped Form Control of a Selector Type +/// Base Class used for any Grouped Form Control of a Selector Type. open class SelectorGroupHandlerBase: Control, Changeable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// Array of the HandlerType registered - public var selectorViews: [HandlerType] = [] + /// Array of the HandlerType registered. + open var selectorViews: [HandlerType] = [] /// The primary subscriber for onChange or the UIControl valueChanged event. - public var onChangeSubscriber: AnyCancellable? { + open var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { onChangeSubscriber.cancel() } } } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - /// Override to update the child SelectorViews disabled property for this group - override public var disabled: Bool { + /// Whether this object is disabled or not + override open var disabled: Bool { didSet { selectorViews.forEach { handler in handler.disabled = disabled @@ -41,29 +37,33 @@ open class SelectorGroupHandlerBase: Control, Changeable { } } - /// Override to update the child SelectorViews surface property for this group - override public var surface: Surface { + /// Current Surface and this is used to pass down to child objects that implement Surfacable. + override open var surface: Surface { didSet { selectorViews.forEach { handler in handler.surface = surface } } } + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- - /// Handler for the Group to override on a select event - /// - Parameter selectedControl: Selected Control the user interacted + /// Handler for the Group to override on a select event. + /// - Parameter selectedControl: Selected Control the user interacted. open func didSelect(_ selectedControl: HandlerType) { fatalError("Must override didSelect") } - /// Helper method to execute the valueChanged event - public func valueChanged() { + /// Helper method to execute the valueChanged event. + open func valueChanged() { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.sendActions(for: .valueChanged) } } - /// Override to update the child SelectorViews reset method for this group + /// Resets to default settings as well as child views. open override func reset() { super.reset() selectorViews.forEach{ $0.reset() } @@ -77,7 +77,7 @@ open class SelectorGroupHandlerBase: Control, Changeable { open class SelectorGroupSelectedHandlerBase: SelectorGroupHandlerBase{ - /// Current Selected Control for this group + /// Current Selected Control for this group. public var selectedHandler: HandlerType? { return selectorViews.filter { $0.isSelected == true }.first } diff --git a/VDS/Classes/SelectorItemBase.swift b/VDS/Classes/SelectorItemBase.swift index de49b09a..b7c916b2 100644 --- a/VDS/Classes/SelectorItemBase.swift +++ b/VDS/Classes/SelectorItemBase.swift @@ -11,7 +11,8 @@ import Combine import VDSColorTokens import VDSFormControlsTokens -open class SelectorItemBase: Control, Errorable, Changeable { +/// Generic Control used to build out a SelectorControlable control. +open class SelectorItemBase: Control, Errorable, Changeable, FormFieldable { //-------------------------------------------------- // MARK: - Initializers @@ -61,6 +62,7 @@ open class SelectorItemBase: Control, Errorable, //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + /// Subscriber that is set for the .valueChanged event. open var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { @@ -69,32 +71,40 @@ open class SelectorItemBase: Control, Errorable, } } + /// Label used to render labelText. open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left $0.textStyle = .boldBodyLarge } + /// Label used to render childText. open var childLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left $0.textStyle = .bodyLarge } + /// Label used to render errorText. open var errorLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left $0.textStyle = .bodyMedium } - + + /// Generic Object used to allow the user to 'Select'. open var selectorView = Selector() - + + /// Whether or not ths Item is selected. open override var isSelected: Bool { didSet { setNeedsUpdate() }} - + + /// Text shown in the label. open var labelText: String? { didSet { setNeedsUpdate() }} - + + /// Array of LabelAttributeModel objects used in rendering the labelText. open var labelTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} + /// Instead of use labelText and labelTextAttirbutes, this is a fully baked NSAttributedString with both text and attributes. open var labelAttributedText: NSAttributedString? { didSet { label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true) @@ -103,10 +113,13 @@ open class SelectorItemBase: Control, Errorable, } } + /// Text shown in the childLabel. open var childText: String? { didSet { setNeedsUpdate() }} + /// Array of LabelAttributeModel objects used in rendering the childText. open var childTextAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} + /// Instead of use childText and childTextAttirbutes, this is a fully baked NSAttributedString with both text and attributes. open var childAttributedText: NSAttributedString? { didSet { childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true) @@ -114,18 +127,8 @@ open class SelectorItemBase: Control, Errorable, setNeedsUpdate() } } - - var _showError: Bool = false - open var showError: Bool { - get { _showError } - set { - if !isSelected && _showError != newValue { - _showError = newValue - setNeedsUpdate() - } - } - } + /// Override UIControl state to add the .error state if showError is true. open override var state: UIControl.State { get { var state = super.state @@ -136,13 +139,24 @@ open class SelectorItemBase: Control, Errorable, } } + var _showError: Bool = false + + open var showError: Bool { + get { _showError } + set { + if !isSelected && _showError != newValue { + _showError = newValue + setNeedsUpdate() + } + } + } + open var errorText: String? { didSet { setNeedsUpdate() }} open var inputId: String? { didSet { setNeedsUpdate() }} open var value: AnyHashable? { didSet { setNeedsUpdate() }} - //functions //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -169,7 +183,52 @@ open class SelectorItemBase: Control, Errorable, selectorLabelStackView.addArrangedSubview(childLabel) mainStackView.pinToSuperView() } + + /// Function used to make changes to the View based off a change events or from local properties. + open override func updateView() { + super.updateView() + updateLabels() + selectorView.showError = showError + selectorView.isSelected = isSelected + selectorView.isHighlighted = isHighlighted + selectorView.disabled = disabled + selectorView.surface = surface + } + + open override func updateAccessibility() { + super.updateAccessibility() + setAccessibilityLabel(for: [label, childLabel, errorLabel]) + } + + /// Resets to default settings. + open override func reset() { + super.reset() + shouldUpdateView = false + label.reset() + childLabel.reset() + errorLabel.reset() + + label.textStyle = .boldBodyLarge + childLabel.textStyle = .bodyLarge + errorLabel.textStyle = .bodyMedium + + labelText = nil + labelTextAttributes = nil + labelAttributedText = nil + childText = nil + childTextAttributes = nil + childAttributedText = nil + showError = false + errorText = nil + inputId = nil + value = nil + isSelected = false + + shouldUpdateView = true + setNeedsUpdate() + } + /// Update all labels with Text as well as adding and removing the labels. func updateLabels() { //deal with labels @@ -225,53 +284,8 @@ open class SelectorItemBase: Control, Errorable, errorLabel.isHidden = true } } - - /// Resets back to this objects default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - label.reset() - childLabel.reset() - errorLabel.reset() - - label.textStyle = .boldBodyLarge - childLabel.textStyle = .bodyLarge - errorLabel.textStyle = .bodyMedium - - labelText = nil - labelTextAttributes = nil - labelAttributedText = nil - childText = nil - childTextAttributes = nil - childAttributedText = nil - showError = false - errorText = nil - inputId = nil - value = nil - isSelected = false - - shouldUpdateView = true - setNeedsUpdate() - } - - /// This will checkbox the state of the Selector and execute the actionBlock if provided. - open func toggle() {} - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- - open override func updateView() { - updateLabels() - selectorView.showError = showError - selectorView.isSelected = isSelected - selectorView.isHighlighted = isHighlighted - selectorView.disabled = disabled - selectorView.surface = surface - updateAccessibility() - } - open override func updateAccessibility() { - super.updateAccessibility() - setAccessibilityLabel(for: [label, childLabel, errorLabel]) - } + /// This will change to state of the Selector. + open func toggle() {} + } diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index dbedd80e..d42e30f9 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -9,13 +9,13 @@ import Foundation import UIKit @objc(VDSSelfSizingCollectionView) -/// UICollectionView subclassed used to deal with Changing the size of itself based on its children and layout and changes of its contentSize +/// UICollectionView subclassed used to deal with Changing the size of itself based on its children and layout and changes of its contentSize. public final class SelfSizingCollectionView: UICollectionView { private var contentSizeObservation: NSKeyValueObservation? //-------------------------------------------------- - // MARK: - Lifecycle + // MARK: - Initialization //-------------------------------------------------- /// Initializer @@ -71,9 +71,9 @@ public final class SelfSizingCollectionView: UICollectionView { extension UITraitCollection { - /// Used within SelfSizingCollectionView to determine if there is an appearance change - /// - Parameter traitCollection: TraitCollection to compare - /// - Returns: True/False based on the trailCollection passed in + /// Used within SelfSizingCollectionView to determine if there is an appearance change. + /// - Parameter traitCollection: TraitCollection to compare. + /// - Returns: True/False based on the trailCollection passed in. public func hasDifferentTextAppearance(comparedTo traitCollection: UITraitCollection?) -> Bool { var result = self.preferredContentSizeCategory != traitCollection?.preferredContentSizeCategory result = result || self.legibilityWeight != traitCollection?.legibilityWeight diff --git a/VDS/Classes/View.swift b/VDS/Classes/View.swift index 199fadcb..8f1e40a3 100644 --- a/VDS/Classes/View.swift +++ b/VDS/Classes/View.swift @@ -9,15 +9,15 @@ import Foundation import UIKit import Combine - @objc(VDSView) /// Base Class used to build Views. -open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { +open class View: UIView, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- - public var subscribers = Set() + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() //-------------------------------------------------- // MARK: - Properties @@ -27,13 +27,13 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true - /// Dictionary for keeping information for this Control use only Primitives + /// Dictionary for keeping information for this Control use only Primitives. open var userInfo = [String: Primitive]() /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() } } - /// Whether this object is disabled or not + /// Whether this object is disabled or not. open var disabled: Bool { get { !isEnabled } set { @@ -43,6 +43,7 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { } } + /// Whether the View is enabled or not. open var isEnabled: Bool = true { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } //-------------------------------------------------- @@ -64,10 +65,10 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { } //-------------------------------------------------- - // MARK: - Setup + // MARK: - Lifecycle //-------------------------------------------------- - /// Executed on initialization for this View + /// Executed on initialization for this View. open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true @@ -76,16 +77,18 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { } } - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - - /// Update this view based off of property changes - open func updateView() { - updateAccessibility() + /// Will be called only once and should be overridden in subclasses to setup UI or defaults. + open func setup() { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + insetsLayoutMarginsFromSafeArea = false } - /// Used to update any Accessibility properties + /// Function used to make changes to the View based off a change events or from local properties.. + open func updateView() { + } + + /// Used to update any Accessibility properties. open func updateAccessibility() { if isEnabled { accessibilityTraits.remove(.notEnabled) @@ -94,17 +97,11 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { } } - /// Resets to the Views default values + /// Resets to default settings. open func reset() { backgroundColor = .clear surface = .light disabled = false } - /// Will be called only once and should be overridden in subclasses to setup UI or defaults - open func setup() { - backgroundColor = .clear - translatesAutoresizingMaskIntoConstraints = false - insetsLayoutMarginsFromSafeArea = false - } } diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index 321753f9..bf2ff583 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -41,7 +41,7 @@ open class Badge: View { /// The text that will be shown in the label. open var text: String = "" { didSet { setNeedsUpdate() }} - /// When applied, this property takes a px value that will restrict the width at that point + /// When applied, this property takes a px value that will restrict the width at that point. open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }} /// This will restrict the badge height to a specific number of lines. If the text overflows the allowable space, ellipsis will show. @@ -53,6 +53,46 @@ open class Badge: View { private var maxWidthConstraint: NSLayoutConstraint? private var minWidthConstraint: NSLayoutConstraint? + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + + /// ColorConfiguration that is mapped to the 'fillColor' for the surface. + private var backgroundColorConfiguration: AnyColorable = { + let config = KeyedColorConfiguration(keyPath: \.fillColor) + config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) + config.setSurfaceColors(VDSColor.paletteYellow53, VDSColor.paletteYellow53, forKey: .yellow) + config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forKey: .green) + config.setSurfaceColors(VDSColor.paletteOrange41, VDSColor.paletteOrange58, forKey: .orange) + config.setSurfaceColors(VDSColor.paletteBlue38, VDSColor.paletteBlue46, forKey: .blue) + config.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryDark, forKey: .black) + config.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forKey: .white) + return config.eraseToAnyColorable() + }() + + /// ColorConfiguration for the Text. + private var textColorConfiguration = ViewColorConfiguration() + + /// Updates the textColorConfiguration based on the fillColor. + public func updateTextColorConfig() { + textColorConfiguration.reset() + + switch fillColor { + + 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) + } + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -75,9 +115,9 @@ open class Badge: View { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { - super.reset() + super.reset() shouldUpdateView = false label.reset() label.lineBreakMode = .byTruncatingTail @@ -91,50 +131,10 @@ open class Badge: View { setNeedsUpdate() } - //-------------------------------------------------- - // MARK: - Configuration - //-------------------------------------------------- - - /// ColorConfiguration that is mapped to the 'fillColor' for the surface - private var backgroundColorConfiguration: AnyColorable = { - let config = KeyedColorConfiguration(keyPath: \.fillColor) - config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) - config.setSurfaceColors(VDSColor.paletteYellow53, VDSColor.paletteYellow53, forKey: .yellow) - config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forKey: .green) - config.setSurfaceColors(VDSColor.paletteOrange41, VDSColor.paletteOrange58, forKey: .orange) - config.setSurfaceColors(VDSColor.paletteBlue38, VDSColor.paletteBlue46, forKey: .blue) - config.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryDark, forKey: .black) - config.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forKey: .white) - return config.eraseToAnyColorable() - }() - - /// ColorConfiguration for the Text - private var textColorConfiguration = ViewColorConfiguration() - - /// Updates the textColorConfiguration based on the fillColor - public func updateTextColorConfig() { - textColorConfiguration.reset() - - switch fillColor { - - 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) - } - } - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + updateTextColorConfig() backgroundColor = backgroundColorConfiguration.getColor(self) diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index d35b7187..1a00abfc 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -19,17 +19,17 @@ open class BadgeIndicator: View { // MARK: - Enums //-------------------------------------------------- - /// Enum type for fill color + /// Enum type for fill color. public enum FillColor: String, CaseIterable { case red, yellow, green, orange, blue, gray, grayLowContrast, black, white } - /// Enum type for kind of BadgeIndicator + /// Enum type for kind of BadgeIndicator. public enum Kind: String, CaseIterable { case simple, numbered } - /// Enum type for maximum number of digits + /// Enum type for maximum number of digits. public enum MaximumDigits: String, CaseIterable { case one case two @@ -59,7 +59,7 @@ open class BadgeIndicator: View { } } - /// Enum type describing size of Badge Indicator + /// Enum type describing size of Badge Indicator. public enum Size: String, CaseIterable { case xxlarge = "2XLarge" case xlarge = "XLarge" @@ -67,7 +67,7 @@ open class BadgeIndicator: View { case medium = "Medium" case small = "Small" - /// Dynamic TextStyle for the size + /// Dynamic TextStyle for the size. public var textStyle: TextStyle { let style = TextStyle.bodySmall var pointSize: CGFloat = VDSTypography.fontSizeBody12 @@ -98,7 +98,7 @@ open class BadgeIndicator: View { letterSpacing: letterSpacing) } - //EdgeInsets for the label + //EdgeInsets for the label. public var edgeInset: UIEdgeInsets { var horizontalPadding: CGFloat = VDSLayout.Spacing.space1X.value let verticalPadding: CGFloat = 0 @@ -120,7 +120,7 @@ open class BadgeIndicator: View { // MARK: - Public Properties //-------------------------------------------------- - /// Label used for the numeric kind + /// Label used for the numeric kind. open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.adjustsFontSizeToFitWidth = false @@ -129,7 +129,7 @@ open class BadgeIndicator: View { $0.numberOfLines = 1 } - /// BorderColor for Surface.light + /// BorderColor for Surface.light. open var borderColorLight: UIColor? { didSet { if let borderColorLight { @@ -140,8 +140,8 @@ open class BadgeIndicator: View { setNeedsUpdate() } } - - /// BorderColor for Surface.dark + + /// BorderColor for Surface.dark. open var borderColorDark: UIColor? { didSet { if let borderColorDark { @@ -157,40 +157,40 @@ open class BadgeIndicator: View { /// When used in conjunction with the surface prop, this fill color will change its tint automatically based on a light or dark surface. open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }} - /// Badge Number that will be shown if you are using Kind.numbered + /// Badge Number that will be shown if you are using Kind.numbered. open var number: Int? { didSet { setNeedsUpdate() }} /// Type of Badge Indicator, simple is a dot, whereas numbered shows a number. open var kind: Kind = .simple { didSet { setNeedsUpdate() }} - /// Character that is always at the begging. Accepts any character and if unaffected by maximumDigits + /// Character that is always at the begging. Accepts any character and if unaffected by maximumDigits. open var leadingCharacter: String? { didSet { setNeedsUpdate() }} /// Determines the size of the Badge Indicator as well as the textStyle and padding used. open var size: Size = .xxlarge { didSet { setNeedsUpdate() }} - /// Pixel size of the dot when the kind is set to simple + /// Pixel size of the dot when the kind is set to simple. open var dotSize: CGFloat? { didSet { setNeedsUpdate() }} - /// Sets the padding at the top/bottom of the label + /// Sets the padding at the top/bottom of the label. open var verticalPadding: CGFloat? { didSet { setNeedsUpdate() }} - /// Sets the padding at the left/right of the label + /// Sets the padding at the left/right of the label. open var horitonalPadding: CGFloat? { didSet { setNeedsUpdate() }} /// Hides the dot when you are in Kind.simple mode. open var hideDot: Bool = false { didSet { setNeedsUpdate() }} - /// Will not show the border + /// Will not show the border. open var hideBorder: Bool = false { didSet { setNeedsUpdate() }} /// When in Kind.numbered this is the amount of digits that will show up when the user adds a number. open var maximumDigits: MaximumDigits = .two { didSet { setNeedsUpdate() }} - /// The Container's width + /// The Container's width. open var width: CGFloat? { didSet { setNeedsUpdate() }} - /// The Container's height + /// The Container's height. open var height: CGFloat? { didSet { setNeedsUpdate() }} //-------------------------------------------------- @@ -278,7 +278,7 @@ open class BadgeIndicator: View { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -310,10 +310,10 @@ open class BadgeIndicator: View { } } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + updateTextColorConfig() badgeView.backgroundColor = backgroundColorConfiguration.getColor(self) @@ -372,6 +372,10 @@ open class BadgeIndicator: View { return min(number, maxNumber) } + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override func layoutSubviews() { super.layoutSubviews() diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index be1a7cec..f81e3b40 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -130,7 +130,7 @@ open class Button: ButtonBase, Useable { heightConstraint?.isActive = true } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -149,8 +149,10 @@ open class Button: ButtonBase, Useable { return CGSize(width: width > size.minimumWidth ? width : size.minimumWidth, height: size.height) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() + let bgColor = backgroundColorConfiguration.getColor(self) let borderColor = borderColorConfiguration.getColor(self) let borderWidth = use == .secondary ? VDSFormControls.widthBorder : 0.0 diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 637fceb3..2f1e23b5 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -18,7 +18,7 @@ public protocol Buttonable: UIControl, Surfaceable, Disabling { } @objc(VDSButtonBase) -open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable { +open class ButtonBase: UIButton, Buttonable, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Configuration Properties @@ -28,8 +28,10 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- - public var subscribers = Set() - public var onClickSubscriber: AnyCancellable? { + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() + + open var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() @@ -45,21 +47,23 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true open var availableSizes: [ButtonSize] { [] } open var text: String? { didSet { setNeedsUpdate() } } - open var attributes: [any LabelAttributeModel]? { nil } + open var textAttributes: [any LabelAttributeModel]? { nil } open var useScaledFont: Bool = false { didSet { setNeedsUpdate() }} - + + /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() }} open var userInfo = [String: Primitive]() - public var touchUpInsideCount: Int = 0 + open var touchUpInsideCount: Int = 0 internal var isHighlightAnimating = false @@ -68,11 +72,11 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab if isHighlightAnimating == false && touchUpInsideCount > 0 { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in - self?.updateView() + self?.setNeedsUpdate() }) { [weak self] _ in //you update the view since this is typically a quick change UIView.animate(withDuration: 0.1, animations: { [weak self] in - self?.updateView() + self?.setNeedsUpdate() self?.isHighlightAnimating = false }) } @@ -90,6 +94,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab } } + /// Whether the Control is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } open var textStyle: TextStyle { .defaultStyle } @@ -135,7 +140,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab } - /// Resets back to this objects default settings. + /// Resets to default settings. open func reset() { shouldUpdateView = false surface = .light @@ -156,9 +161,9 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab return CGSize(width: adjustedWidth, height: adjustedHeight) } + /// Function used to make changes to the View based off a change events or from local properties. open func updateView() { updateLabel() - updateAccessibility() } open func updateAccessibility() { @@ -185,7 +190,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab alignment: titleLabel?.textAlignment ?? .center, lineBreakMode: titleLabel?.lineBreakMode ?? .byTruncatingTail) - if let attributes = attributes { + if let attributes = textAttributes { //loop through the models attributes for attribute in attributes { //add attribute on the string diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 9f845f96..99aef7f5 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -29,7 +29,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega open var rowQuantityTablet: Int = 0 { didSet { setNeedsUpdate() } } - public var rowQuantity: Int { UIDevice.isIPad ? rowQuantityTablet : rowQuantityPhone } + open var rowQuantity: Int { UIDevice.isIPad ? rowQuantityTablet : rowQuantityPhone } //If provided, aligns TextLink/TextLinkCaret alignment when rowQuantity is set one. open var buttonPosition: ButtonPosition = .center { didSet { setNeedsUpdate() }} @@ -93,7 +93,8 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - override public var disabled: Bool { + /// Whether this object is disabled or not + override open var disabled: Bool { didSet { buttons.forEach { button in var b = button @@ -101,8 +102,9 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega } } } - - override public var surface: Surface { + + /// Current Surface and this is used to pass down to child objects that implement Surfacable + override open var surface: Surface { didSet { buttons.forEach { button in var b = button @@ -137,6 +139,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() positionLayout.position = buttonPosition diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 573665e0..ca7aac1d 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -87,7 +87,7 @@ open class TextLink: ButtonBase { } } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -107,6 +107,7 @@ open class TextLink: ButtonBase { return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { //need to set the properties so the super class //can render out the label correctly diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index c7c14e74..a41ebfb0 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -30,7 +30,7 @@ open class TextLinkCaret: ButtonBase { private var imageAttribute: CaretLabelAttribute? - open override var attributes: [any LabelAttributeModel]? { + open override var textAttributes: [any LabelAttributeModel]? { guard let imageAttribute else { return nil } return [imageAttribute] } @@ -79,7 +79,7 @@ open class TextLinkCaret: ButtonBase { accessibilityTraits = .link } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() iconPosition = .right @@ -94,6 +94,7 @@ open class TextLinkCaret: ButtonBase { return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { imageAttribute = CaretLabelAttribute(tintColor: textColor, position: iconPosition) super.updateView() diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index 03635d4d..763a18ab 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -14,13 +14,13 @@ open class CheckboxGroup: SelectorGroupHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var selectedHandlers: [CheckboxItem]? { + open var selectedHandlers: [CheckboxItem]? { let selected = selectorViews.filter{ $0.isSelected == true } guard selected.count > 0 else { return nil } return selected } - public override var selectorViews: [CheckboxItem] { + open override var selectorViews: [CheckboxItem] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } @@ -35,7 +35,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { } } - public var selectorModels: [CheckboxModel]? { + open var selectorModels: [CheckboxModel]? { didSet { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in @@ -61,7 +61,7 @@ open class CheckboxGroup: SelectorGroupHandlerBase { } private var _showError: Bool = false - public var showError: Bool { + open var showError: Bool { get { _showError } set { var newShowError = newValue @@ -112,7 +112,9 @@ open class CheckboxGroup: SelectorGroupHandlerBase { extension CheckboxGroup { public struct CheckboxModel : Surfaceable, Disabling, Initable, FormFieldable, Errorable { + /// Whether this object is disabled or not public var disabled: Bool + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? diff --git a/VDS/Components/Checkbox/CheckboxItem.swift b/VDS/Components/Checkbox/CheckboxItem.swift index 675aa7cc..994eca5e 100644 --- a/VDS/Components/Checkbox/CheckboxItem.swift +++ b/VDS/Components/Checkbox/CheckboxItem.swift @@ -44,6 +44,7 @@ open class CheckboxItem: SelectorItemBase { sendActions(for: .valueChanged) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { selectorView.isAnimated = isAnimated super.updateView() diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 5d7c63ba..00efaca1 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -253,7 +253,7 @@ open class ButtonIcon: Control { iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -268,6 +268,7 @@ open class ButtonIcon: Control { setNeedsUpdate() } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -284,6 +285,10 @@ open class ButtonIcon: Control { setNeedsLayout() } + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override func layoutSubviews() { super.layoutSubviews() diff --git a/VDS/Components/Icon/Icon.swift b/VDS/Components/Icon/Icon.swift index 58a712fb..0c496793 100644 --- a/VDS/Components/Icon/Icon.swift +++ b/VDS/Components/Icon/Icon.swift @@ -62,16 +62,14 @@ open class Icon: View { accessibilityTraits = .image } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() color = VDSColor.paletteBlack imageView.image = nil } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() //get the color for the image diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 2ea9f227..d77e03fe 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -17,6 +17,7 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable private var size: Tooltip.Size = .small public var location: Int = 0 public var length: Int = 3 + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface = .light public var accessibleText: String? = "Tool Tip" public var closeButtonText: String = "Close" diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 092b48a2..27f3fd79 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -11,24 +11,27 @@ import VDSColorTokens import Combine @objc(VDSLabel) -open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { +open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- - public var subscribers = Set() + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- private var initialSetupPerformed = false + /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true open var useAttributedText: Bool = false open var useScaledFont: Bool = false { didSet { setNeedsUpdate() }} + /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { setNeedsUpdate() }} open var attributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() }} @@ -58,12 +61,13 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { } } + /// Whether the View is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate(); isUserInteractionEnabled = isEnabled } } //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- - public var textColorConfiguration: AnyColorable = ViewColorConfiguration().with { + open var textColorConfiguration: AnyColorable = ViewColorConfiguration().with { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable(){ didSet { setNeedsUpdate() }} @@ -111,7 +115,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { open func setup() {} - /// Resets back to this objects default settings. + /// Resets to default settings. open func reset() { shouldUpdateView = false surface = .light @@ -136,7 +140,8 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { //-------------------------------------------------- // MARK: - Overrides - //-------------------------------------------------- + //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open func updateView() { if !useAttributedText { if let text = text { @@ -154,10 +159,7 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { //set the attributed text attributedText = mutableText - - //get accessibility - updateAccessibility() - + //force a drawText setNeedsDisplay() } diff --git a/VDS/Components/Line/Line.swift b/VDS/Components/Line/Line.swift index 18bb485f..c9c33aba 100644 --- a/VDS/Components/Line/Line.swift +++ b/VDS/Components/Line/Line.swift @@ -28,6 +28,16 @@ open class Line: View { open var style: Style = .primary { didSet { setNeedsUpdate() } } + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + open var lineViewColorConfiguration: AnyColorable = { + let config = KeyedColorConfiguration(keyPath: \.style) + config.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forKey: .primary) + config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary) + return config.eraseToAnyColorable() + }() + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -40,26 +50,16 @@ open class Line: View { lineView.pinToSuperView() } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() style = .primary } - //-------------------------------------------------- - // MARK: - Configuration - //-------------------------------------------------- - public var lineViewColorConfiguration: AnyColorable = { - let config = KeyedColorConfiguration(keyPath: \.style) - config.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forKey: .primary) - config.setSurfaceColors(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark, forKey: .secondary) - return config.eraseToAnyColorable() - }() - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + lineView.backgroundColor = lineViewColorConfiguration.getColor(self) } } diff --git a/VDS/Components/Loader/Loader.swift b/VDS/Components/Loader/Loader.swift index 582eaf2b..9c67b6e2 100644 --- a/VDS/Components/Loader/Loader.swift +++ b/VDS/Components/Loader/Loader.swift @@ -24,10 +24,10 @@ open class Loader: View { // MARK: - Public Properties //-------------------------------------------------- /// Loader will be active if 'active' prop is passed. - public var isActive: Bool = true { didSet { setNeedsUpdate() } } + open var isActive: Bool = true { didSet { setNeedsUpdate() } } /// The Int used to determine the height and width of the Loader - public var size: Int = 40 { didSet { setNeedsUpdate() } } + open var size: Int = 40 { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Lifecycle @@ -46,6 +46,7 @@ open class Loader: View { ]) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() icon.color = iconColorConfiguration.getColor(self) diff --git a/VDS/Components/Loader/LoaderViewController.swift b/VDS/Components/Loader/LoaderViewController.swift index 7e18c0c1..d64e7a74 100644 --- a/VDS/Components/Loader/LoaderViewController.swift +++ b/VDS/Components/Loader/LoaderViewController.swift @@ -20,7 +20,7 @@ open class LoaderViewController: UIViewController, Surfaceable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// Current Surface used within this Control and used to passdown to child views + /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { updateView() }} /// Size of the Height and Width of the Loader view. @@ -43,7 +43,7 @@ open class LoaderViewController: UIViewController, Surfaceable { updateView() } - /// Update this view based off of property chang + /// Function used to make changes to the View based off a change events or from local properties. open func updateView() { view.backgroundColor = backgroundColorConfiguration.getColor(self).withAlphaComponent(0.8) if let size { diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index de382de3..3e704b5e 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -90,8 +90,9 @@ open class Notification: View { open var leadingConstraint: NSLayoutConstraint? open var trailingConstraint: NSLayoutConstraint? + //-------------------------------------------------- - // MARK: - View Properties + // MARK: - Public Properties //-------------------------------------------------- open var typeIcon = Icon().with { @@ -228,7 +229,7 @@ open class Notification: View { subTitleLabel.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() @@ -263,10 +264,10 @@ open class Notification: View { setNeedsUpdate() } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + backgroundColor = backgroundColorConfiguration.getColor(self) updateIcons() updateLabels() diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index 0742459f..209a5769 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -30,7 +30,7 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { } } - public var selectorModels: [RadioBoxModel]? { + open var selectorModels: [RadioBoxModel]? { didSet { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in @@ -107,7 +107,9 @@ open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { extension RadioBoxGroup { public struct RadioBoxModel: Surfaceable, Initable, Disabling, FormFieldable { + /// Whether this object is disabled or not public var disabled: Bool + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 9da920ef..e789785e 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -56,7 +56,7 @@ open class RadioBoxItem: Control, Changeable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var onChangeSubscriber: AnyCancellable? { + open var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { onChangeSubscriber.cancel() @@ -82,7 +82,7 @@ open class RadioBoxItem: Control, Changeable { $0.textStyle = .bodyLarge } - public var selectorView = UIView().with { + open var selectorView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } @@ -127,8 +127,29 @@ open class RadioBoxItem: Control, Changeable { open var inputId: String? { didSet { setNeedsUpdate() }} open var value: AnyHashable? { didSet { setNeedsUpdate() }} - - //functions + + //-------------------------------------------------- + // MARK: - Configuration Properties + //-------------------------------------------------- + private var strikeThroughLineThickness: CGFloat = VDSFormControls.widthBorder + private var selectorCornerRadius: CGFloat = VDSFormControls.borderradius + private var selectorBorderWidthSelected: CGFloat = VDSFormControls.widthBorder + VDSFormControls.widthBorder + private var selectorBorderWidth: CGFloat = VDSFormControls.widthBorder + + private var backgroundColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .selected) + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .highlighted) + } + + private var borderColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -200,7 +221,7 @@ open class RadioBoxItem: Control, Changeable { } } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -238,12 +259,11 @@ open class RadioBoxItem: Control, Changeable { sendActions(for: .valueChanged) } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + updateLabels() - updateAccessibility() setNeedsLayout() layoutIfNeeded() } @@ -255,28 +275,6 @@ open class RadioBoxItem: Control, Changeable { } } - //-------------------------------------------------- - // MARK: - Configuration Properties - //-------------------------------------------------- - private var strikeThroughLineThickness: CGFloat = VDSFormControls.widthBorder - private var selectorCornerRadius: CGFloat = VDSFormControls.borderradius - private var selectorBorderWidthSelected: CGFloat = VDSFormControls.widthBorder + VDSFormControls.widthBorder - private var selectorBorderWidth: CGFloat = VDSFormControls.widthBorder - - private var backgroundColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) - $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) - $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .selected) - $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .highlighted) - } - - private var borderColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - } - //-------------------------------------------------- // MARK: - RadioBox View Updates //-------------------------------------------------- diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 1ffa55bb..4298f827 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -30,7 +30,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { } } - public var selectorModels: [RadioButtonModel]? { + open var selectorModels: [RadioButtonModel]? { didSet { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in @@ -56,7 +56,7 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { } private var _showError: Bool = false - public var showError: Bool { + open var showError: Bool { get { _showError } set { var newShowError = newValue @@ -116,7 +116,9 @@ open class RadioButtonGroup: SelectorGroupSelectedHandlerBase { extension RadioButtonGroup { public struct RadioButtonModel: Surfaceable, Disabling, Initable, FormFieldable, Errorable { + /// Whether this object is disabled or not public var disabled: Bool + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? diff --git a/VDS/Components/RadioSwatch/RadioSwatch.swift b/VDS/Components/RadioSwatch/RadioSwatch.swift index f6651bdd..1658482d 100644 --- a/VDS/Components/RadioSwatch/RadioSwatch.swift +++ b/VDS/Components/RadioSwatch/RadioSwatch.swift @@ -32,11 +32,11 @@ open class RadioSwatch: Control { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var selectorView = UIView().with { + open var selectorView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } - public var fillView = UIImageView().with { + open var fillView = UIImageView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.contentMode = .scaleAspectFit } @@ -55,7 +55,22 @@ open class RadioSwatch: Control { open var value: AnyHashable? { didSet { setNeedsUpdate() }} - //functions + //-------------------------------------------------- + // MARK: - Configuration Properties + //-------------------------------------------------- + private var strikeThroughLineThickness: CGFloat = VDSFormControls.widthBorder + private var selectorBorderWidth: CGFloat = VDSFormControls.widthBorder + public let swatchSize = CGSize(width: 48, height: 48) + public let fillSize = CGSize(width: 36, height: 36) + public let disabledAlpha = 0.5 + + private var borderColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -89,7 +104,7 @@ open class RadioSwatch: Control { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -110,33 +125,19 @@ open class RadioSwatch: Control { sendActions(for: .valueChanged) } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + layer.setNeedsDisplay() } public override func updateAccessibility() { + super.updateAccessibility() + accessibilityLabel = text } - //-------------------------------------------------- - // MARK: - Configuration Properties - //-------------------------------------------------- - private var strikeThroughLineThickness: CGFloat = VDSFormControls.widthBorder - private var selectorBorderWidth: CGFloat = VDSFormControls.widthBorder - public let swatchSize = CGSize(width: 48, height: 48) - public let fillSize = CGSize(width: 36, height: 36) - public let disabledAlpha = 0.5 - - private var borderColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - } - //-------------------------------------------------- // MARK: - RadioBox View Updates //-------------------------------------------------- @@ -148,7 +149,10 @@ open class RadioSwatch: Control { open func getSelectorSize() -> CGSize { return swatchSize } - + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- open override func layoutSubviews() { super.layoutSubviews() // Accounts for any size changes diff --git a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift index e5211163..25827392 100644 --- a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift +++ b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift @@ -21,7 +21,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo } } - public var selectorModels: [RadioSwatchModel]? { + open var selectorModels: [RadioSwatchModel]? { didSet { if let selectorModels { selectorViews = selectorModels.map { model in @@ -46,7 +46,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - public var label = Label() + open var label = Label() private let cellSize: CGFloat = 48.0 private let labelSpacing: CGFloat = 24.0 private let labelHeight: CGFloat = 16.0 @@ -71,6 +71,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + /// Whether this object is disabled or not override public var disabled: Bool { didSet { for selector in selectorViews { @@ -79,7 +80,7 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo collectionView.reloadData() } } - + /// Current Surface and this is used to pass down to child objects that implement Surfacable override public var surface: Surface { didSet { for selector in selectorViews { @@ -123,7 +124,10 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo collectionView.dataSource = self } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() + label.textPosition = .left label.textStyle = .bodySmall label.text = selectedHandler?.text ?? " " @@ -190,7 +194,9 @@ open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICo extension RadioSwatchGroup { public struct RadioSwatchModel: Surfaceable, Disabling, Initable { + /// Whether this object is disabled or not public var disabled: Bool = false + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? diff --git a/VDS/Components/Tabs/Tab.swift b/VDS/Components/Tabs/Tab.swift index 4720fabe..ded6aa62 100644 --- a/VDS/Components/Tabs/Tab.swift +++ b/VDS/Components/Tabs/Tab.swift @@ -146,6 +146,7 @@ extension Tabs { layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index 59cfda95..fd7327fe 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -232,6 +232,7 @@ open class Tabs: View { } } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/Tabs/TabsContainer.swift b/VDS/Components/Tabs/TabsContainer.swift index ccb01c1c..50eab591 100644 --- a/VDS/Components/Tabs/TabsContainer.swift +++ b/VDS/Components/Tabs/TabsContainer.swift @@ -140,6 +140,7 @@ open class TabsContainer: View { ]) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/TextFields/EntryField/EntryField.swift b/VDS/Components/TextFields/EntryField/EntryField.swift index d485c007..819e805e 100644 --- a/VDS/Components/TextFields/EntryField/EntryField.swift +++ b/VDS/Components/TextFields/EntryField/EntryField.swift @@ -98,7 +98,7 @@ open class EntryField: Control, Changeable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var onChangeSubscriber: AnyCancellable? { + open var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { onChangeSubscriber.cancel() @@ -228,7 +228,7 @@ open class EntryField: Control, Changeable { return containerView } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() titleLabel.reset() @@ -258,10 +258,9 @@ open class EntryField: Control, Changeable { readOnly = false } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { + super.updateView() containerView.backgroundColor = backgroundColorConfiguration.getColor(self) containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 8ee35f0e..f6df3da8 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -103,7 +103,7 @@ open class InputField: EntryField, UITextFieldDelegate { $0.font = TextStyle.bodyLarge.font } - public var textFieldTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { + open var textFieldTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable() @@ -140,7 +140,7 @@ open class InputField: EntryField, UITextFieldDelegate { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() textField.text = "" @@ -161,6 +161,7 @@ open class InputField: EntryField, UITextFieldDelegate { return inputFieldStackView } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 9064c9fc..eb7e45e0 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -53,13 +53,14 @@ open class TextArea: EntryField { $0.isScrollEnabled = false } - public var textViewTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { + open var textViewTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) - }.eraseToAnyColorable() + }.eraseToAnyColorable() { didSet { setNeedsUpdate() }} internal var minWidthConstraint: NSLayoutConstraint? internal var textViewHeightConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -79,7 +80,7 @@ open class TextArea: EntryField { textView.delegate = self } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() textView.text = "" @@ -90,9 +91,7 @@ open class TextArea: EntryField { return inputFieldStackView } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 6b5eef20..e96f9f04 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -77,26 +77,26 @@ open class TileContainer: Control { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public var backgroundImage: UIImage? { didSet{ setNeedsUpdate() } } + open var backgroundImage: UIImage? { didSet{ setNeedsUpdate() } } - public var containerView = View().with { + open var containerView = View().with { $0.isUserInteractionEnabled = false } - public var highlightView = View().with { + open var highlightView = View().with { $0.isUserInteractionEnabled = false } - public var color: BackgroundColor = .white { didSet{ setNeedsUpdate() } } + open var color: BackgroundColor = .white { didSet{ setNeedsUpdate() } } - public var padding: Padding = .padding4X { didSet{ setNeedsUpdate() } } + open var padding: Padding = .padding4X { didSet{ setNeedsUpdate() } } - public var aspectRatio: AspectRatio = .ratio1x1 { didSet{ setNeedsUpdate() } } + open var aspectRatio: AspectRatio = .ratio1x1 { didSet{ setNeedsUpdate() } } - public var imageFallbackColor: Surface = .light { didSet{ setNeedsUpdate() } } + open var imageFallbackColor: Surface = .light { didSet{ setNeedsUpdate() } } private var _width: CGFloat? - public var width: CGFloat? { + open var width: CGFloat? { get { return _width } set { if let newValue, newValue > 100 { @@ -109,7 +109,7 @@ open class TileContainer: Control { } private var _height: CGFloat? - public var height: CGFloat? { + open var height: CGFloat? { get { return _height } set { if let newValue, newValue > 44 { @@ -121,9 +121,9 @@ open class TileContainer: Control { } } - public var showBorder: Bool = false { didSet{ setNeedsUpdate() } } + open var showBorder: Bool = false { didSet{ setNeedsUpdate() } } - public var showDropShadows: Bool = false { didSet{ setNeedsUpdate() } } + open var showDropShadows: Bool = false { didSet{ setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties @@ -145,7 +145,6 @@ open class TileContainer: Control { internal var containerLeadingConstraint: NSLayoutConstraint? internal var containerTrailingConstraint: NSLayoutConstraint? - //functions //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -189,7 +188,7 @@ open class TileContainer: Control { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -205,64 +204,7 @@ open class TileContainer: Control { setNeedsUpdate() } - //-------------------------------------------------- - // MARK: - Configuration - //-------------------------------------------------- - private let cornerRadius = VDSFormControls.borderradius * 2 - - private var backgroundColorConfiguration = BackgroundColorConfiguration() - - private var borderColorConfiguration = SurfaceColorConfiguration().with { - $0.lightColor = VDSColor.elementsLowcontrastOnlight - $0.darkColor = VDSColor.elementsLowcontrastOndark - } - - private var imageFallbackColorConfiguration = SurfaceColorConfiguration().with { - $0.lightColor = VDSColor.backgroundPrimaryLight - $0.darkColor = VDSColor.backgroundPrimaryDark - } - - private var hightLightViewColorConfiguration = SurfaceColorConfiguration().with { - $0.lightColor = VDSColor.paletteWhite.withAlphaComponent(0.3) - $0.darkColor = VDSColor.paletteBlack.withAlphaComponent(0.3) - } - - //-------------------------------------------------- - // MARK: - Private Functions - //-------------------------------------------------- - private func ratioSize(for width: CGFloat) -> CGSize { - var height: CGFloat = width - - switch aspectRatio { - case .ratio1x1: - break; - case .ratio3x4: - height = (4 / 3) * width - case .ratio4x3: - height = (3 / 4) * width - case .ratio2x3: - height = (3 / 2) * width - case .ratio3x2: - height = (2 / 3) * width - case .ratio9x16: - height = (16 / 9) * width - case .ratio16x9: - height = (9 / 16) * width - case .ratio1x2: - height = (2 / 1) * width - case .ratio2x1: - height = (1 / 2) * width - - default: - break - } - - return CGSize(width: width, height: height) - } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -319,6 +261,62 @@ open class TileContainer: Control { view.pinToSuperView() } } + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + private let cornerRadius = VDSFormControls.borderradius * 2 + + private var backgroundColorConfiguration = BackgroundColorConfiguration() + + private var borderColorConfiguration = SurfaceColorConfiguration().with { + $0.lightColor = VDSColor.elementsLowcontrastOnlight + $0.darkColor = VDSColor.elementsLowcontrastOndark + } + + private var imageFallbackColorConfiguration = SurfaceColorConfiguration().with { + $0.lightColor = VDSColor.backgroundPrimaryLight + $0.darkColor = VDSColor.backgroundPrimaryDark + } + + private var hightLightViewColorConfiguration = SurfaceColorConfiguration().with { + $0.lightColor = VDSColor.paletteWhite.withAlphaComponent(0.3) + $0.darkColor = VDSColor.paletteBlack.withAlphaComponent(0.3) + } + + //-------------------------------------------------- + // MARK: - Private Functions + //-------------------------------------------------- + private func ratioSize(for width: CGFloat) -> CGSize { + var height: CGFloat = width + + switch aspectRatio { + case .ratio1x1: + break; + case .ratio3x4: + height = (4 / 3) * width + case .ratio4x3: + height = (3 / 4) * width + case .ratio2x3: + height = (3 / 2) * width + case .ratio3x2: + height = (2 / 3) * width + case .ratio9x16: + height = (16 / 9) * width + case .ratio16x9: + height = (9 / 16) * width + case .ratio1x2: + height = (2 / 1) * width + case .ratio2x1: + height = (1 / 2) * width + + default: + break + } + + return CGSize(width: width, height: height) + } + } extension TileContainer { diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 80c66ea0..0de18f58 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -162,13 +162,13 @@ open class Tilelet: TileContainer { open var textPostion: TextPosition = .top { didSet { setNeedsUpdate() }} //models - public var badgeModel: BadgeModel? { didSet { setNeedsUpdate() }} - public var titleModel: TitleModel? { didSet { setNeedsUpdate() }} - public var subTitleModel: SubTitleModel? { didSet { setNeedsUpdate() }} + open var badgeModel: BadgeModel? { didSet { setNeedsUpdate() }} + open var titleModel: TitleModel? { didSet { setNeedsUpdate() }} + open var subTitleModel: SubTitleModel? { didSet { setNeedsUpdate() }} //only 1 Icon can be active private var _descriptiveIconModel: DescriptiveIcon? - public var descriptiveIconModel: DescriptiveIcon? { + open var descriptiveIconModel: DescriptiveIcon? { get { _descriptiveIconModel } set { _descriptiveIconModel = newValue; @@ -178,7 +178,7 @@ open class Tilelet: TileContainer { } private var _directionalIconModel: DirectionalIcon? - public var directionalIconModel: DirectionalIcon? { + open var directionalIconModel: DirectionalIcon? { get { _directionalIconModel } set { _directionalIconModel = newValue; @@ -194,7 +194,7 @@ open class Tilelet: TileContainer { //-------------------------------------------------- internal var titleLockupWidthConstraint: NSLayoutConstraint? internal var titleLockupTrailingConstraint: NSLayoutConstraint? - //functions + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -240,7 +240,7 @@ open class Tilelet: TileContainer { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { shouldUpdateView = false aspectRatio = .none @@ -255,9 +255,6 @@ open class Tilelet: TileContainer { setNeedsUpdate() } - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- fileprivate func updateBadge() { if let badgeModel { badge.text = badgeModel.text @@ -368,6 +365,7 @@ open class Tilelet: TileContainer { } } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -376,10 +374,11 @@ open class Tilelet: TileContainer { updateIcons() layoutIfNeeded() - updateAccessibility() } open override func updateAccessibility() { + super.updateAccessibility() + setAccessibilityLabel(for: [badge.label, titleLockup.eyebrowLabel, titleLockup.titleLabel, titleLockup.subTitleLabel]) } } diff --git a/VDS/Components/Tilelet/TileletBadgeModel.swift b/VDS/Components/Tilelet/TileletBadgeModel.swift index bd7efcac..a56d034a 100644 --- a/VDS/Components/Tilelet/TileletBadgeModel.swift +++ b/VDS/Components/Tilelet/TileletBadgeModel.swift @@ -11,6 +11,7 @@ extension Tilelet { public struct BadgeModel { public var text: String = "" public var fillColor: Badge.FillColor + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var numberOfLines: Int public var maxWidth: CGFloat? diff --git a/VDS/Components/Tilelet/TileletIconModels.swift b/VDS/Components/Tilelet/TileletIconModels.swift index 22a5a148..eb9e444e 100644 --- a/VDS/Components/Tilelet/TileletIconModels.swift +++ b/VDS/Components/Tilelet/TileletIconModels.swift @@ -13,6 +13,7 @@ extension Tilelet { public struct DescriptiveIcon { public var name: Icon.Name public var size: Icon.Size + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public init(name: Icon.Name = .multipleDocuments, size: Icon.Size = .medium, surface: Surface = .dark) { diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index ab745a33..bf3ea8f0 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -46,11 +46,44 @@ open class TitleLockup: View { $0.distribution = .fill } + private var otherStandardStyle: OtherStandardStyle { + if let subTitleModel, !subTitleModel.text.isEmpty { + return subTitleModel.standardStyle + } else if let eyebrowModel, !eyebrowModel.text.isEmpty { + return eyebrowModel.standardStyle + } else { + return .bodyLarge + } + } + ///This logic applies when the type style and size used for the title and subtitle/eyebrow is exactly the same (not including the type weight). This should be automatically detected. private var isUniformSize: Bool { otherStandardStyle.value == titleModel?.standardStyle.value } + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var textPosition: TextPosition = .left { didSet { setNeedsUpdate() }} + + //first row + open var eyebrowLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + } + open var eyebrowModel: EyebrowModel? { didSet { setNeedsUpdate() }} + + //second row + open var titleLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + } + open var titleModel: TitleModel? { didSet { setNeedsUpdate() }} + + //third row + open var subTitleLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + } + open var subTitleModel: SubTitleModel? { didSet { setNeedsUpdate() }} + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -217,29 +250,6 @@ open class TitleLockup: View { private var textColorSecondaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight).eraseToAnyColorable() private var textColorPrimaryConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark).eraseToAnyColorable() - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - open var textPosition: TextPosition = .left { didSet { setNeedsUpdate() }} - - //first row - open var eyebrowLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - } - open var eyebrowModel: EyebrowModel? { didSet { setNeedsUpdate() }} - - //second row - open var titleLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - } - open var titleModel: TitleModel? { didSet { setNeedsUpdate() }} - - //third row - open var subTitleLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - } - open var subTitleModel: SubTitleModel? { didSet { setNeedsUpdate() }} //-------------------------------------------------- // MARK: - Lifecycle @@ -263,7 +273,7 @@ open class TitleLockup: View { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -275,19 +285,7 @@ open class TitleLockup: View { setNeedsUpdate() } - private var otherStandardStyle: OtherStandardStyle { - if let subTitleModel, !subTitleModel.text.isEmpty { - return subTitleModel.standardStyle - } else if let eyebrowModel, !eyebrowModel.text.isEmpty { - return eyebrowModel.standardStyle - } else { - return .bodyLarge - } - } - - //-------------------------------------------------- - // MARK: - State - //-------------------------------------------------- + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -378,5 +376,5 @@ open class TitleLockup: View { eyebrowLabel.isHidden = eyebrowTextIsEmpty titleLabel.isHidden = titleTextIsEmpty subTitleLabel.isHidden = subTitleTextIsEmpty - } + } } diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index e7b50206..82a602b2 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -172,7 +172,7 @@ open class Toggle: Control, Changeable { } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -191,6 +191,26 @@ open class Toggle: Control, Changeable { setNeedsUpdate() } + /// Function used to make changes to the View based off a change events or from local properties. + open override func updateView() { + super.updateView() + + updateLabel() + toggleView.surface = surface + toggleView.disabled = disabled + toggleView.isOn = isOn + } + + open override func updateAccessibility() { + super.updateAccessibility() + + if showText { + setAccessibilityLabel(for: [label]) + } else { + accessibilityLabel = "Toggle" + } + } + /// This will toggle the state of the Toggle open func toggle() { isOn.toggle() @@ -231,23 +251,7 @@ open class Toggle: Control, Changeable { //-------------------------------------------------- // MARK: - Overrides - //-------------------------------------------------- - open override func updateView() { - updateLabel() - toggleView.surface = surface - toggleView.disabled = disabled - toggleView.isOn = isOn - updateAccessibility() - } - - open override func updateAccessibility() { - super.updateAccessibility() - if showText { - setAccessibilityLabel(for: [label]) - } else { - accessibilityLabel = "Toggle" - } - } + //-------------------------------------------------- open override var intrinsicContentSize: CGSize { if showLabel { diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index b19afeed..672c7305 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -34,7 +34,11 @@ open class ToggleView: Control, Changeable { public required init?(coder: NSCoder) { super.init(coder: coder) } - + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var toggleView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.isUserInteractionEnabled = false @@ -46,6 +50,27 @@ open class ToggleView: Control, Changeable { $0.isUserInteractionEnabled = false } + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var onChangeSubscriber: AnyCancellable? + + open var isOn: Bool { + get { isSelected } + set { + if isSelected != newValue { + isSelected = newValue + } + setNeedsUpdate() + } + } + + open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} + + open var inputId: String? { didSet { setNeedsUpdate() }} + + open var value: AnyHashable? { didSet { setNeedsUpdate() }} + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -66,28 +91,7 @@ open class ToggleView: Control, Changeable { $0.setSurfaceColors(VDSColor.paletteGray95, VDSColor.paletteGray44, forState: [.selected, .disabled]) $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forState: .selected) } - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - public var onChangeSubscriber: AnyCancellable? - - open var isOn: Bool { - get { isSelected } - set { - if isSelected != newValue { - isSelected = newValue - } - setNeedsUpdate() - } - } - open var isAnimated: Bool = true { didSet { setNeedsUpdate() }} - - open var inputId: String? { didSet { setNeedsUpdate() }} - - open var value: AnyHashable? { didSet { setNeedsUpdate() }} - //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -133,10 +137,8 @@ open class ToggleView: Control, Changeable { setContentHuggingPriority(.required, for: .horizontal) setContentHuggingPriority(.required, for: .vertical) } - - open override var intrinsicContentSize: CGSize { toggleSize } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -150,12 +152,30 @@ open class ToggleView: Control, Changeable { setNeedsUpdate() } + /// Function used to make changes to the View based off a change events or from local properties. + open override func updateView() { + super.updateView() + + updateToggle() + } + + open override func updateAccessibility() { + super.updateAccessibility() + + accessibilityLabel = "Toggle" + } + /// This will toggle the state of the Toggle and execute the actionBlock if provided. open func toggle() { isOn.toggle() sendActions(for: .valueChanged) } + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override var intrinsicContentSize: CGSize { toggleSize } + //-------------------------------------------------- // MARK: - Toggle //-------------------------------------------------- @@ -193,19 +213,6 @@ open class ToggleView: Control, Changeable { }, completion: nil) } } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - open override func updateView() { - updateToggle() - updateAccessibility() - } - - open override func updateAccessibility() { - super.updateAccessibility() - accessibilityLabel = "Toggle" - } } // MARK: AppleGuidlinesTouchable diff --git a/VDS/Components/Tooltip/Tooltip.swift b/VDS/Components/Tooltip/Tooltip.swift index 5df97beb..c522137f 100644 --- a/VDS/Components/Tooltip/Tooltip.swift +++ b/VDS/Components/Tooltip/Tooltip.swift @@ -126,7 +126,7 @@ open class Tooltip: Control, TooltipLaunchable { backgroundColor = .clear isAccessibilityElement = true - accessibilityTraits = .link + accessibilityTraits = .button onClickSubscriber = publisher(for: .touchUpInside) .sink(receiveValue: { [weak self] tooltip in @@ -140,7 +140,7 @@ open class Tooltip: Control, TooltipLaunchable { }) } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -154,6 +154,7 @@ open class Tooltip: Control, TooltipLaunchable { setNeedsUpdate() } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -174,11 +175,13 @@ open class Tooltip: Control, TooltipLaunchable { if label == nil { label = content } + if let label, !label.isEmpty { + accessibilityLabel = label + } else { + accessibilityLabel = "Tooltip" + } accessibilityHint = isEnabled ? "Click to open Tooltip." : "" accessibilityValue = "collapsed" - if let label { - accessibilityLabel = label - } } public static func accessibleText(for title: String?, content: String?, closeButtonText: String) -> String { diff --git a/VDS/Components/Tooltip/TooltipAlertViewController.swift b/VDS/Components/Tooltip/TooltipAlertViewController.swift index 01aa8f09..2be0d921 100644 --- a/VDS/Components/Tooltip/TooltipAlertViewController.swift +++ b/VDS/Components/Tooltip/TooltipAlertViewController.swift @@ -12,8 +12,8 @@ import VDSColorTokens open class TooltipAlertViewController: UIViewController, Surfaceable { - /// Set of Subscribers for any Publishers for this Control - public var subscribers = Set() + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() //-------------------------------------------------- // MARK: - Private Properties @@ -31,12 +31,14 @@ open class TooltipAlertViewController: UIViewController, Surfaceable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + /// Current Surface and this is used to pass down to child objects that implement Surfacable open var surface: Surface = .light { didSet { updateView() }} open var titleText: String? { didSet { updateView() }} open var contentText: String? { didSet { updateView() }} open var contentView: UIView? { didSet { updateView() }} open var closeButtonText: String = "Close" { didSet { updateView() }} open var presenter: UIView? { didSet { updateView() }} + //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- @@ -62,6 +64,9 @@ open class TooltipAlertViewController: UIViewController, Surfaceable { } } + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- open func setup() { view.accessibilityElements = [tooltipDialog] @@ -100,214 +105,13 @@ open class TooltipAlertViewController: UIViewController, Surfaceable { ]) } + /// Function used to make changes to the View based off a change events or from local properties. open func updateView() { view.backgroundColor = backgroundColorConfiguration.getColor(self).withAlphaComponent(0.3) tooltipDialog.surface = surface tooltipDialog.titleText = titleText tooltipDialog.contentText = contentText tooltipDialog.contentView = contentView - } -} - -open class TooltipDialog: View, UIScrollViewDelegate { - - private var scrollView = UIScrollView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.backgroundColor = .clear - } - - private let contentStackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.axis = .vertical - $0.distribution = .fillProportionally - $0.spacing = 0 - } - - private var line = Line().with { instance in - instance.lineViewColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable() - } - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - open var titleText: String? { didSet { setNeedsUpdate() }} - open var titleLabel = Label().with { label in - label.textStyle = .boldTitleMedium - } - - open var contentText: String? { didSet { setNeedsUpdate() }} - open var contentLabel = Label().with { label in - label.textStyle = .bodyLarge - } - - open var contentView: UIView? = nil - - open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }} - - open lazy var closeButton: UIButton = { - let button = UIButton(type: .system) - button.backgroundColor = .clear - button.setTitle("Close", for: .normal) - button.titleLabel?.font = TextStyle.bodyLarge.font - button.translatesAutoresizingMaskIntoConstraints = false - return button - }() - - //-------------------------------------------------- - // MARK: - Configuration - //-------------------------------------------------- - private var closeButtonHeight: CGFloat = 44.0 - private var fullWidth: CGFloat = 296 - private var minHeight: CGFloat = 96.0 - private var maxHeight: CGFloat = 312.0 - private let containerViewInset = VDSLayout.Spacing.space4X.value - - private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) - private let closeButtonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) - - private var contentStackViewBottomConstraint: NSLayoutConstraint? - private var heightConstraint: NSLayoutConstraint? - - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - open override func setup() { - super.setup() - layer.cornerRadius = 8 - contentStackView.isAccessibilityElement = true - contentStackView.addArrangedSubview(titleLabel) - contentStackView.addArrangedSubview(contentLabel) - scrollView.addSubview(contentStackView) - addSubview(scrollView) - addSubview(line) - addSubview(closeButton) - - // Activate constraints - NSLayoutConstraint.activate([ - widthAnchor.constraint(equalToConstant: fullWidth), - - // Constraints for the scroll view - scrollView.topAnchor.constraint(equalTo: topAnchor, constant: VDSLayout.Spacing.space4X.value), - scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), - scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), - scrollView.bottomAnchor.constraint(equalTo: line.topAnchor), - - line.leadingAnchor.constraint(equalTo: leadingAnchor), - line.trailingAnchor.constraint(equalTo: trailingAnchor), - - closeButton.topAnchor.constraint(equalTo: line.bottomAnchor), - closeButton.leadingAnchor.constraint(equalTo: leadingAnchor), - closeButton.trailingAnchor.constraint(equalTo: trailingAnchor), - closeButton.bottomAnchor.constraint(equalTo: bottomAnchor), - closeButton.heightAnchor.constraint(equalToConstant: closeButtonHeight), - - contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor), - contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: containerViewInset), - contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -containerViewInset), - contentStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -(containerViewInset * 2)), - - ]) - contentStackViewBottomConstraint = contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor) - contentStackViewBottomConstraint?.activate() - - heightConstraint = heightAnchor.constraint(equalToConstant: minHeight) - heightConstraint?.activate() - } - - open override func updateView() { - super.updateView() - - backgroundColor = backgroundColorConfiguration.getColor(self) - scrollView.indicatorStyle = surface == .light ? .black : .white - - titleLabel.removeFromSuperview() - contentLabel.removeFromSuperview() - contentView?.removeFromSuperview() - - titleLabel.surface = surface - contentLabel.surface = surface - line.surface = surface - - titleLabel.text = titleText - contentLabel.text = contentText - - titleLabel.sizeToFit() - contentLabel.sizeToFit() - - var addedTitle = false - - if let titleText, !titleText.isEmpty { - contentStackView.addArrangedSubview(titleLabel) - addedTitle = true - } - - var addedContent = false - if let contentText, !contentText.isEmpty { - contentStackView.addArrangedSubview(contentLabel) - addedContent = true - } else if let contentView { - contentView.translatesAutoresizingMaskIntoConstraints = false - if var surfaceable = contentView as? Surfaceable { - surfaceable.surface = surface - } - let wrapper = View() - wrapper.addSubview(contentView) - contentView.pinTop() - contentView.pinLeading() - contentView.pinBottom() - contentView.pinTrailingLessThanOrEqualTo() - contentView.setNeedsLayout() - contentStackView.addArrangedSubview(wrapper) - addedContent = true - } - - if addedTitle && addedContent { - contentStackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: titleLabel) - } - - let closeButtonTextColor = closeButtonTextColorConfiguration.getColor(self) - closeButton.setTitleColor(closeButtonTextColor, for: .normal) - closeButton.setTitleColor(closeButtonTextColor, for: .highlighted) - closeButton.setTitle(closeButtonText, for: .normal) - closeButton.accessibilityLabel = closeButtonText - - contentStackView.setNeedsLayout() - contentStackView.layoutIfNeeded() - - scrollView.setNeedsLayout() - scrollView.layoutIfNeeded() - - //dealing with height - //we can't really use the minMax height and set constraints for - //greaterThan or lessThan on the heightAnchor due to scrollView/stackView intrinsic size - //therefore we can do a little math and manually set the height based off all of the content - var contentHeight = closeButtonHeight + scrollView.contentSize.height + (containerViewInset * 2) - - //reset the bottomConstraint - contentStackViewBottomConstraint?.constant = 0 - - if contentHeight < minHeight { - contentHeight = minHeight - - } else if contentHeight > maxHeight { - contentHeight = maxHeight - //since we are now scrolling, add padding to the bottom of the - //stackView between the bottom of the scrollView - contentStackViewBottomConstraint?.constant = -containerViewInset - } - - heightConstraint?.constant = contentHeight - } - - open override func updateAccessibility() { - var label = Tooltip.accessibleText(for: titleText, content: contentText, closeButtonText: closeButtonText) - if !label.isEmpty { - label += "," - } - - contentStackView.accessibilityLabel = label - contentStackView.accessibilityHint = "Click on the \(closeButtonText) button to close." - contentStackView.accessibilityValue = "expanded" - accessibilityElements = [contentStackView, closeButton] + tooltipDialog.closeButtonText = closeButtonText } } diff --git a/VDS/Components/Tooltip/TooltipDialog.swift b/VDS/Components/Tooltip/TooltipDialog.swift new file mode 100644 index 00000000..ae8aeddd --- /dev/null +++ b/VDS/Components/Tooltip/TooltipDialog.swift @@ -0,0 +1,227 @@ +// +// TooltipDialog.swift +// VDS +// +// Created by Matt Bruce on 8/8/23. +// + +import Foundation +import UIKit +import VDSColorTokens + +open class TooltipDialog: View, UIScrollViewDelegate { + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + + private var scrollView = UIScrollView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + } + + private let contentStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .vertical + $0.distribution = .fillProportionally + $0.spacing = 0 + } + + private var line = Line().with { instance in + instance.lineViewColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable() + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var titleText: String? { didSet { setNeedsUpdate() }} + open var titleLabel = Label().with { label in + label.isAccessibilityElement = true + label.textStyle = .boldTitleMedium + } + + open var contentText: String? { didSet { setNeedsUpdate() }} + open var contentLabel = Label().with { label in + label.isAccessibilityElement = true + label.textStyle = .bodyLarge + } + + open var contentView: UIView? = nil + + open var closeButtonText: String = "Close" { didSet { setNeedsUpdate() }} + + open lazy var closeButton: UIButton = { + let button = UIButton(type: .system) + button.isAccessibilityElement = true + button.backgroundColor = .clear + button.setTitle("Close", for: .normal) + button.titleLabel?.font = TextStyle.bodyLarge.font + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + private var closeButtonHeight: CGFloat = 44.0 + private var fullWidth: CGFloat = 296 + private var minHeight: CGFloat = 96.0 + private var maxHeight: CGFloat = 312.0 + private let containerViewInset = VDSLayout.Spacing.space4X.value + + private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) + private let closeButtonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + + private var contentStackViewBottomConstraint: NSLayoutConstraint? + private var heightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func setup() { + super.setup() + + layer.cornerRadius = 8 + contentStackView.addArrangedSubview(titleLabel) + contentStackView.addArrangedSubview(contentLabel) + scrollView.addSubview(contentStackView) + addSubview(scrollView) + addSubview(line) + addSubview(closeButton) + + // Activate constraints + NSLayoutConstraint.activate([ + widthAnchor.constraint(equalToConstant: fullWidth), + + // Constraints for the scroll view + scrollView.topAnchor.constraint(equalTo: topAnchor, constant: VDSLayout.Spacing.space4X.value), + scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: line.topAnchor), + + line.leadingAnchor.constraint(equalTo: leadingAnchor), + line.trailingAnchor.constraint(equalTo: trailingAnchor), + + closeButton.topAnchor.constraint(equalTo: line.bottomAnchor), + closeButton.leadingAnchor.constraint(equalTo: leadingAnchor), + closeButton.trailingAnchor.constraint(equalTo: trailingAnchor), + closeButton.bottomAnchor.constraint(equalTo: bottomAnchor), + closeButton.heightAnchor.constraint(equalToConstant: closeButtonHeight), + + contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor), + contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: containerViewInset), + contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -containerViewInset), + contentStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -(containerViewInset * 2)), + + ]) + contentStackViewBottomConstraint = contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor) + contentStackViewBottomConstraint?.activate() + + heightConstraint = heightAnchor.constraint(equalToConstant: minHeight) + heightConstraint?.activate() + } + + /// Function used to make changes to the View based off a change events or from local properties. + open override func updateView() { + super.updateView() + + backgroundColor = backgroundColorConfiguration.getColor(self) + scrollView.indicatorStyle = surface == .light ? .black : .white + + titleLabel.removeFromSuperview() + contentLabel.removeFromSuperview() + contentView?.removeFromSuperview() + + titleLabel.surface = surface + contentLabel.surface = surface + line.surface = surface + + titleLabel.text = titleText + contentLabel.text = contentText + + titleLabel.sizeToFit() + contentLabel.sizeToFit() + + var addedTitle = false + + if let titleText, !titleText.isEmpty { + contentStackView.addArrangedSubview(titleLabel) + addedTitle = true + } + + var addedContent = false + if let contentText, !contentText.isEmpty { + contentStackView.addArrangedSubview(contentLabel) + addedContent = true + } else if let contentView { + contentView.translatesAutoresizingMaskIntoConstraints = false + if var surfaceable = contentView as? Surfaceable { + surfaceable.surface = surface + } + let wrapper = View() + wrapper.addSubview(contentView) + contentView.pinTop() + contentView.pinLeading() + contentView.pinBottom() + contentView.pinTrailingLessThanOrEqualTo() + contentView.setNeedsLayout() + contentStackView.addArrangedSubview(wrapper) + addedContent = true + } + + if addedTitle && addedContent { + contentStackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: titleLabel) + } + + let closeButtonTextColor = closeButtonTextColorConfiguration.getColor(self) + closeButton.setTitleColor(closeButtonTextColor, for: .normal) + closeButton.setTitleColor(closeButtonTextColor, for: .highlighted) + closeButton.setTitle(closeButtonText, for: .normal) + closeButton.accessibilityLabel = closeButtonText + + contentStackView.setNeedsLayout() + contentStackView.layoutIfNeeded() + + scrollView.setNeedsLayout() + scrollView.layoutIfNeeded() + + //dealing with height + //we can't really use the minMax height and set constraints for + //greaterThan or lessThan on the heightAnchor due to scrollView/stackView intrinsic size + //therefore we can do a little math and manually set the height based off all of the content + var contentHeight = closeButtonHeight + scrollView.contentSize.height + (containerViewInset * 2) + + //reset the bottomConstraint + contentStackViewBottomConstraint?.constant = 0 + + if contentHeight < minHeight { + contentHeight = minHeight + + } else if contentHeight > maxHeight { + contentHeight = maxHeight + //since we are now scrolling, add padding to the bottom of the + //stackView between the bottom of the scrollView + contentStackViewBottomConstraint?.constant = -containerViewInset + } + + heightConstraint?.constant = contentHeight + } + + lazy var primaryAccessibilityElement = UIAccessibilityElement(accessibilityContainer: self).with { + $0.accessibilityLabel = "Tooltip" + $0.accessibilityValue = "expanded" + $0.accessibilityFrameInContainerSpace = .init(origin: .zero, size: .init(width: fullWidth, height: VDSLayout.Spacing.space1X.value)) + } + + open override func updateAccessibility() { + super.updateAccessibility() + + primaryAccessibilityElement.accessibilityHint = "Click on the \(closeButtonText) button to close." + + var elements: [Any] = [primaryAccessibilityElement] + contentStackView.arrangedSubviews.forEach{ elements.append($0) } + elements.append(closeButton) + + accessibilityElements = elements + } + +} diff --git a/VDS/Components/Tooltip/TrailingTooltipLabel.swift b/VDS/Components/Tooltip/TrailingTooltipLabel.swift index 6986dd3a..4a1be607 100644 --- a/VDS/Components/Tooltip/TrailingTooltipLabel.swift +++ b/VDS/Components/Tooltip/TrailingTooltipLabel.swift @@ -62,6 +62,7 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { }.store(in: &subscribers) } + /// Function used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -78,7 +79,7 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { } } - /// Resets back to this objects default settings. + /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false @@ -97,6 +98,7 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { extension Label { public struct TooltipModel { + /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var closeButtonText: String public var title: String? diff --git a/VDS/Extensions/UIView+Accessibility.swift b/VDS/Extensions/UIView+Accessibility.swift new file mode 100644 index 00000000..6c785c5e --- /dev/null +++ b/VDS/Extensions/UIView+Accessibility.swift @@ -0,0 +1,27 @@ +// +// UIView+Accessibility.swift +// VDS +// +// Created by Matt Bruce on 8/4/23. +// + +import Foundation +import UIKit + +extension UIView { + /// AccessibilityLabel helper for joining the accessibilityLabel property of all views passed in. + /// - Parameters: + /// - views: Array of Views that you want to join the accessibilityLabel. + /// - separator: Separator used between the accessibilityLabel for each UIView. + /// - Returns: Joined String. + public func combineAccessibilityLabel(for views: [UIView], separator: String = ", ") -> String? { + let labels = views.map({($0.accessibilityLabel?.isEmpty ?? true) ? nil : $0.accessibilityLabel}).compactMap({$0}) + return labels.joined(separator: separator) + } + + /// AccessibilityLabel helper for joining the accessibilityLabel property of all views passed in. + /// - Parameter views: Array of Views that you want to join the accessibilityLabel. + public func setAccessibilityLabel(for views: [UIView]) { + accessibilityLabel = combineAccessibilityLabel(for: views) + } +} diff --git a/VDS/Extensions/UIView+CALayer.swift b/VDS/Extensions/UIView+CALayer.swift index 05e60113..f8d9f25e 100644 --- a/VDS/Extensions/UIView+CALayer.swift +++ b/VDS/Extensions/UIView+CALayer.swift @@ -62,7 +62,7 @@ extension UIView { } else { removeDebugBorder() } - if let view = self as? Handlerable { + if let view = self as? ViewProtocol { view.updateView() } } diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView+NSLayoutConstraint.swift similarity index 100% rename from VDS/Extensions/UIView.swift rename to VDS/Extensions/UIView+NSLayoutConstraint.swift diff --git a/VDS/Fonts/Font.swift b/VDS/Fonts/Font.swift index ecd692de..c5caaa32 100644 --- a/VDS/Fonts/Font.swift +++ b/VDS/Fonts/Font.swift @@ -9,23 +9,23 @@ import Foundation /// Enum that is matched up for the Verizon fonts. public enum Font: String, FontProtocol { - case dsBold - case dsRegular + case edsBold + case edsRegular case dsLight - case txBold - case txRegular + case etxBold + case etxRegular public var fontName: String { switch self { - case .dsBold: + case .edsBold: return "VerizonNHGeDS-Bold" - case .dsRegular: + case .edsRegular: return "VerizonNHGeDS-Regular" case .dsLight: return "VerizonNHGDS-Light" - case .txBold: + case .etxBold: return "VerizonNHGeTX-Bold" - case .txRegular: + case .etxRegular: return "VerizonNHGeTX-Regular" } } diff --git a/VDS/Protocols/Changeable.swift b/VDS/Protocols/Changeable.swift index d51c734b..6ef3eb8e 100644 --- a/VDS/Protocols/Changeable.swift +++ b/VDS/Protocols/Changeable.swift @@ -9,7 +9,8 @@ import Foundation import UIKit import Combine -public protocol Changeable: Handlerable where Self: UIControl { +public protocol Changeable: ViewProtocol where Self: UIControl { + /// Sets the primary Subscriber used for the UIControl event .valueChanged. var onChangeSubscriber: AnyCancellable? { get set } } diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index f98dd1c7..50445dc0 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -9,8 +9,10 @@ import Foundation import UIKit import Combine -public protocol Clickable: Handlerable where Self: UIControl { +public protocol Clickable: ViewProtocol where Self: UIControl { + /// Reference count used when a subscriber is listening for the UIControl event .touchUpInside. var touchUpInsideCount: Int { get set } + /// Sets the primary Subscriber used for the UIControl event .touchUpInside. var onClickSubscriber: AnyCancellable? { get set } } diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 935b3d53..fe015120 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -7,12 +7,12 @@ import Foundation -/// Protocol used for a FormField object +/// Protocol used for a FormField object. public protocol FormFieldable { - /// Unique Id for the Form Field object within a Form + /// Unique Id for the Form Field object within a Form. var inputId: String? { get set } - /// Value for the Form Field + /// Value for the Form Field. var value: AnyHashable? { get set } } diff --git a/VDS/Protocols/Handlerable.swift b/VDS/Protocols/Handlerable.swift deleted file mode 100644 index 14246735..00000000 --- a/VDS/Protocols/Handlerable.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Handlerable.swift -// VDS -// -// Created by Matt Bruce on 7/22/22. -// - -import Foundation -import Combine -import UIKit - -public protocol Handlerable: AnyObject, Initable, Disabling, Surfaceable { - var subscribers: Set { get set } - var shouldUpdateView: Bool { get set } - func updateView() -} - -extension Handlerable { - public func setNeedsUpdate() { - if shouldUpdateView { - shouldUpdateView = false - updateView() - shouldUpdateView = true - } - } -} - -extension Handlerable where Self: UIControl { - public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { - publisher(for: event) - .sink(receiveValue: { c in - block(c) - }).store(in: &subscribers) - } -} diff --git a/VDS/Protocols/Primitive.swift b/VDS/Protocols/Primitive.swift index 30982c67..2e5a72e8 100644 --- a/VDS/Protocols/Primitive.swift +++ b/VDS/Protocols/Primitive.swift @@ -9,5 +9,6 @@ extension Array: Primitive where Element: Primitive {} extension Dictionary: Primitive where Key == String, Value: Primitive {} public protocol UserInfoable { + /// Dictionary for keeping information for the implementing object using only Primitives. var userInfo: [String: Primitive] { get set } } diff --git a/VDS/Protocols/Resetable.swift b/VDS/Protocols/Resetable.swift index 528cba1d..ff180c45 100644 --- a/VDS/Protocols/Resetable.swift +++ b/VDS/Protocols/Resetable.swift @@ -8,6 +8,6 @@ import Foundation public protocol Resettable { - /// Called to reset back an objects default settings. + /// Resets to default settings. func reset() } diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index 63517b35..47b9f9b0 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -7,28 +7,54 @@ import Foundation import UIKit +import Combine -public protocol ViewProtocol { - - // Can setup ui here. Should be called in the initialization functions. +public protocol ViewProtocol: AnyObject, Initable, Resettable, Disabling, Surfaceable { + /// Set of Subscribers for any Publishers for this Control. + var subscribers: Set { get set } + + /// Key of whether or not updateView() is called in setNeedsUpdate() + var shouldUpdateView: Bool { get set } + + /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. func setup() + + /// Function used to make changes to the View based off a change events or from local properties. + func updateView() + + /// Used to update any Accessibility properties. func updateAccessibility() } +extension ViewProtocol { + /// Function called when there are changes in a View based off a change events or from local properties. + public func setNeedsUpdate() { + if shouldUpdateView { + shouldUpdateView = false + updateView() + updateAccessibility() + shouldUpdateView = true + } + } +} + extension ViewProtocol where Self: UIView { + + /// Helper method for removing a superview and updating Self. public func removeFromSuperview(_ view: UIView){ if view.superview != nil { view.removeFromSuperview() setNeedsDisplay() } } +} - public func combineAccessibilityLabel(for views: [UIView]) -> String? { - let labels = views.map({($0.accessibilityLabel?.isEmpty ?? true) ? nil : $0.accessibilityLabel}).compactMap({$0}) - return labels.joined(separator: ", ") - } - - public func setAccessibilityLabel(for views: [UIView]) { - accessibilityLabel = combineAccessibilityLabel(for: views) +extension ViewProtocol where Self: UIControl { + /// Helper function to assign a completion block to a specific UIControl Event using Combine and stored in the subscribers. + public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { + publisher(for: event) + .sink(receiveValue: { c in + block(c) + }).store(in: &subscribers) } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index b135fbc6..d01a5f52 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,10 +1,19 @@ +1.0.37 +======= +- ONEAPP-4684 - Update Accessibility for Tooltip +- Fixed bug in Typography TitleLarge letterSpacing + +1.0.36 +======= +- Fixed bugs in Typography Definitions + 1.0.35 ======= -- ONEAPP-4684 - (Acessibility) Tooltip -- ONEAPP-4681 - (Acessibility) Checkbox -- ONEAPP-4825 - (Acessibility) Radiobutton -- ONEAPP-5104 - (Acessibility) Button -- ONEAPP-4115 - (Acessibility) Tabs +- ONEAPP-4684 - (Accessibility) Tooltip +- ONEAPP-4681 - (Accessibility) Checkbox +- ONEAPP-4825 - (Accessibility) Radiobutton +- ONEAPP-5104 - (Accessibility) Button +- ONEAPP-4115 - (Accessibility) Tabs - TitleLockup update for Janet release 1.0.34 diff --git a/VDS/Typography/Typogprahy+Styles.swift b/VDS/Typography/Typogprahy+Styles.swift index b593f33b..05a6eb64 100644 --- a/VDS/Typography/Typogprahy+Styles.swift +++ b/VDS/Typography/Typogprahy+Styles.swift @@ -12,34 +12,38 @@ import VDSTypographyTokens extension TextStyle { // Static properties for different text styles + + public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, + edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -4)) + public static let featureXLarge = TextStyle(rawValue: "featureXLarge", fontFace: .dsLight, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -4)) - - public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -4)) + public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, + edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -2)) + public static let featureLarge = TextStyle(rawValue: "featureLarge", fontFace: .dsLight, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -2)) - - public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -6: -2)) + public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64, + edgeInsets: .init(bottom: UIDevice.isIPad ? -4: -2)) public static let featureMedium = TextStyle(rawValue: "featureMedium", fontFace: .dsLight, @@ -47,13 +51,12 @@ extension TextStyle { lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64, letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -4: -2)) - - public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -4: -2)) + + public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48, + edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) public static let featureSmall = TextStyle(rawValue: "featureSmall", fontFace: .dsLight, @@ -61,27 +64,25 @@ extension TextStyle { lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48, letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) - - public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) - + + public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40, + edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) + public static let featureXSmall = TextStyle(rawValue: "featureXSmall", fontFace: .dsLight, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40, lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40, letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) - - public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) + + public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40, + edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) public static let title2XLarge = TextStyle(rawValue: "title2XLarge", fontFace: .dsLight, @@ -90,109 +91,92 @@ extension TextStyle { letterSpacing: VDSTypography.letterSpacingSemiWide, edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) - public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40, - letterSpacing: 0, - edgeInsets: .init(bottom: UIDevice.isIPad ? -2: 0)) + public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36) public static let titleXLarge = TextStyle(rawValue: "titleXLarge", fontFace: .dsLight, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32, lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36, letterSpacing: VDSTypography.letterSpacingSemiWide) - - public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36, - letterSpacing: 0) + + public static let boldTitleLarge = TextStyle(rawValue: "boldTitleLarge", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28) public static let titleLarge = TextStyle(rawValue: "titleLarge", - fontFace: .dsLight, + fontFace: UIDevice.isIPad ? .dsLight : .edsRegular, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24, lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28, - letterSpacing: VDSTypography.letterSpacingSemiWide) - - public static let boldTitleLarge = TextStyle(rawValue: "boldTitleLarge", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28, - letterSpacing: 0) - - public static let titleMedium = TextStyle(rawValue: "titleMedium", - fontFace: .dsLight, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24, - letterSpacing: 0) + letterSpacing: UIDevice.isIPad ? VDSTypography.letterSpacingSemiWide : 0) public static let boldTitleMedium = TextStyle(rawValue: "boldTitleMedium", - fontFace: .dsBold, + fontFace: .edsBold, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24, - letterSpacing: 0) + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24) + + public static let titleMedium = TextStyle(rawValue: "titleMedium", + fontFace: .edsRegular, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24) + + public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall", + fontFace: .edsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20) public static let titleSmall = TextStyle(rawValue: "titleSmall", - fontFace: .dsLight, + fontFace: .edsRegular, pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20, - letterSpacing: 0) - - public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall", - fontFace: .dsBold, - pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16, - lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20, - letterSpacing: 0) + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20) + public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge", + fontFace: .edsBold, + pointSize: VDSTypography.fontSizeBody16, + lineHeight: VDSTypography.lineHeightBody20, + letterSpacing: VDSTypography.letterSpacingWide) + public static let bodyLarge = TextStyle(rawValue: "bodyLarge", - fontFace: .dsRegular, + fontFace: .edsRegular, pointSize: VDSTypography.fontSizeBody16, lineHeight: VDSTypography.lineHeightBody20, letterSpacing:VDSTypography.letterSpacingWide) - public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge", - fontFace: .dsBold, - pointSize: VDSTypography.fontSizeBody16, - lineHeight: VDSTypography.lineHeightBody20, - letterSpacing: VDSTypography.letterSpacingWide) - - public static let bodyMedium = TextStyle(rawValue: "bodyMedium", - fontFace: .dsRegular, - pointSize: VDSTypography.fontSizeBody14, - lineHeight: VDSTypography.lineHeightBody18, - letterSpacing: VDSTypography.letterSpacingWide) - public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium", - fontFace: .dsBold, + fontFace: .edsBold, pointSize: VDSTypography.fontSizeBody14, lineHeight: VDSTypography.lineHeightBody18, letterSpacing: VDSTypography.letterSpacingWide) - public static let bodySmall = TextStyle(rawValue: "bodySmall", - fontFace: .dsRegular, - pointSize: VDSTypography.fontSizeBody12, - lineHeight: VDSTypography.lineHeightBody16, - letterSpacing: 0) - + public static let bodyMedium = TextStyle(rawValue: "bodyMedium", + fontFace: .edsRegular, + pointSize: VDSTypography.fontSizeBody14, + lineHeight: VDSTypography.lineHeightBody18, + letterSpacing: VDSTypography.letterSpacingWide) + public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall", - fontFace: .dsBold, + fontFace: .etxBold, pointSize: VDSTypography.fontSizeBody12, - lineHeight: VDSTypography.lineHeightBody16, - letterSpacing: 0) + lineHeight: VDSTypography.lineHeightBody16) - public static let micro = TextStyle(rawValue: "micro", - fontFace: .dsRegular, - pointSize: VDSTypography.fontSizeMicro11, - lineHeight: VDSTypography.lineHeightMicro16, - letterSpacing: 0) + public static let bodySmall = TextStyle(rawValue: "bodySmall", + fontFace: .etxRegular, + pointSize: VDSTypography.fontSizeBody12, + lineHeight: VDSTypography.lineHeightBody16) public static let boldMicro = TextStyle(rawValue: "boldMicro", - fontFace: .dsBold, + fontFace: .etxBold, pointSize: VDSTypography.fontSizeMicro11, - lineHeight: VDSTypography.lineHeightMicro16, - letterSpacing: 0) + lineHeight: VDSTypography.lineHeightMicro16) + public static let micro = TextStyle(rawValue: "micro", + fontFace: .etxRegular, + pointSize: VDSTypography.fontSizeMicro11, + lineHeight: VDSTypography.lineHeightMicro16) + public static var allCases: [TextStyle] { return [ featureXLarge,