refactored everything in the buttons classes to remove buttonable and push configuration inside enums for the classes in question

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2023-09-14 11:47:24 -05:00
parent ad6c00214e
commit 72f2b09255
7 changed files with 87 additions and 123 deletions

View File

@ -11,19 +11,13 @@ import VDSColorTokens
import VDSFormControlsTokens
import Combine
/// Enum used to describe the size of a buttonable.
public enum ButtonSize: String, CaseIterable {
case large
case small
}
/// A button is an interactive element that triggers an action. Buttons are prominent and attention-getting, with more visual emphasis than any of the Text Link components. For this reason, buttons are best suited for critical and driving actions. This class can be used within a ``ButtonGroup``.
///
/// If you are using AutoLayoutConstraints you have a combination of Leading/Left and Trailing/Right NSLayoutConstraints,
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
/// to its parent this object will stretch to the parent's width.
@objc(VDSButton)
open class Button: ButtonBase, Useable, Buttonable {
open class Button: ButtonBase, Useable {
//--------------------------------------------------
// MARK: - Initializers
@ -40,6 +34,50 @@ open class Button: ButtonBase, Useable, Buttonable {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
/// Enum used to describe the size.
public enum Size: String, CaseIterable {
case large
case small
/// Height for this size of button.
public var height: CGFloat {
switch self {
case .large:
return 44
case .small:
return 32
}
}
/// Corner radius for this size of button.
public var cornerRadius: CGFloat {
height / 2
}
/// Minimum width for this size of button.
public var minimumWidth: CGFloat {
switch self {
case .large:
return 76
case .small:
return 60
}
}
/// EdgeInsets for this size of button.
public var edgeInsets: UIEdgeInsets {
switch self {
case .large:
return .axis(horizontal: 24, vertical: 12)
case .small:
return .axis(horizontal: 16, vertical: 8)
}
}
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
@ -48,11 +86,8 @@ open class Button: ButtonBase, Useable, Buttonable {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
/// The ButtonSize available to this type of Buttonable.
open override var availableSizes: [ButtonSize] { [.large, .small] }
/// The ButtonSize for ths Button.
open var size: ButtonSize = .large { didSet { setNeedsUpdate() } }
open var size: Size = .large { didSet { setNeedsUpdate() } }
/// The Use for this Button.
open var use: Use = .primary { didSet { setNeedsUpdate() } }
@ -183,48 +218,6 @@ open class Button: ButtonBase, Useable, Buttonable {
}
}
internal extension ButtonSize {
var height: CGFloat {
switch self {
case .large:
return 44
case .small:
return 32
}
}
var cornerRadius: CGFloat {
height / 2
}
var minimumWidth: CGFloat {
switch self {
case .large:
return 76
case .small:
return 60
}
}
var edgeInsets: UIEdgeInsets {
var verticalPadding = 0.0
var horizontalPadding = 0.0
switch self {
case .large:
verticalPadding = 12
horizontalPadding = 24
break
case .small:
verticalPadding = 8
horizontalPadding = 16
break
}
return UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
}
}
extension Use {
public var color: UIColor {
return self == .primary ? VDSColor.backgroundPrimaryDark : .clear

View File

@ -11,18 +11,6 @@ import VDSColorTokens
import VDSFormControlsTokens
import Combine
public protocol Buttonable: UIControl, Surfaceable, Enabling {
/// The ButtonSize available to this type of Buttonable.
var availableSizes: [ButtonSize] { get }
/// The Text that will show up in the TitleLabel for this Buttonable.
var text: String? { get set }
/// The natural size for the receiving view, considering only properties of the view itself.
var intrinsicContentSize: CGSize { get }
}
/// Base class used for UIButton type classes.
@objc(VDSButtonBase)
open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
@ -45,11 +33,6 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
initialSetup()
}
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
private let hitAreaHeight = 44.0
//--------------------------------------------------
// MARK: - Combine Properties
//--------------------------------------------------
@ -75,9 +58,6 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
/// Key of whether or not updateView() is called in setNeedsUpdate()
open var shouldUpdateView: Bool = true
/// The ButtonSize available to this type of Buttonable.
open var availableSizes: [ButtonSize] { [] }
open var surface: Surface = .light { didSet { setNeedsUpdate() } }
/// Text that will be used in the titleLabel.

View File

@ -60,7 +60,7 @@ open class ButtonGroup: View {
open var alignment: Alignment = .center { didSet { setNeedsUpdate() } }
/// Array of Buttonable Views that are shown in the group.
open var buttons: [Buttonable] = [] { didSet { setNeedsUpdate() } }
open var buttons: [ButtonBase] = [] { didSet { setNeedsUpdate() } }
private var _childWidth: ChildWidth?
@ -205,7 +205,7 @@ extension ButtonGroup: UICollectionViewDataSource, UICollectionViewDelegate {
}
extension ButtonGroup : ButtongGroupPositionLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> Buttonable {
func collectionView(_ collectionView: UICollectionView, buttonBaseAtIndexPath indexPath: IndexPath) -> ButtonBase {
buttons[indexPath.row]
}
}

View File

@ -14,13 +14,13 @@ struct ButtonGroupConstants {
case horizontal, vertical
}
/// This will determine the spacing that will go between 2 buttonables either horizontally or vertically
/// This will determine the spacing that will go between 2 ButtonBases either horizontally or vertically
/// - Parameters:
/// - axis: horizontal/vertical
/// - primary: first buttonable
/// - neighboring: next buttonable based off of axis
/// - primary: first ButtonBase
/// - neighboring: next ButtonBase based off of axis
/// - Returns: float value
static func getSpacing(for axis: ButtonSpacingAxis, with primary: Buttonable, neighboring: Buttonable) -> CGFloat {
static func getSpacing(for axis: ButtonSpacingAxis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat {
//large button
if let button = primary as? Button, button.size == .large {
@ -87,7 +87,7 @@ struct ButtonGroupConstants {
//
/// Gets the tallest buttonables within the row
/// Gets the tallest ButtonBases within the row
/// - Parameter row: Row that includes the attributes
/// - Returns: Array of [ButtonLayoutAttributes] of the tallest items
private static func getTallestAttributes(for row: ButtonCollectionViewRow) -> [ButtonLayoutAttributes] {
@ -122,7 +122,7 @@ struct ButtonGroupConstants {
primaryTallestAttributes.forEach { primaryAttribute in
neighboringTallestAttributes.forEach { neighboringTallestAttribute in
let space = getSpacing(for: .vertical, with: primaryAttribute.buttonable!, neighboring: neighboringTallestAttribute.buttonable!)
let space = getSpacing(for: .vertical, with: primaryAttribute.button!, neighboring: neighboringTallestAttribute.button!)
if space > largestVerticalSpace {
largestVerticalSpace = space
}

View File

@ -82,7 +82,7 @@ class ButtonCollectionViewRow {
}
}
if buttonWidth >= ButtonSize.large.minimumWidth {
if buttonWidth >= Button.Size.large.minimumWidth {
if testSize <= buttonAvailableSpace {
for attribute in attributes {
if attribute.isButton {
@ -122,25 +122,25 @@ class ButtonCollectionViewRow {
protocol ButtongGroupPositionLayoutDelegate: AnyObject {
func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
func collectionView(_ collectionView: UICollectionView, buttonableAtIndexPath indexPath: IndexPath) -> any Buttonable
func collectionView(_ collectionView: UICollectionView, buttonBaseAtIndexPath indexPath: IndexPath) -> ButtonBase
}
class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{
var spacing: CGFloat = 0
var buttonable: Buttonable?
var button: ButtonBase?
var isButton: Bool {
guard buttonable is Button else { return false }
guard button is Button else { return false }
return true
}
convenience init(spacing: CGFloat,
buttonable: Buttonable,
button: ButtonBase,
forCellWith indexPath: IndexPath) {
self.init(forCellWith: indexPath)
self.spacing = spacing
self.buttonable = buttonable
self.button = button
}
}
@ -173,7 +173,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
// Variables to track individual item width and cumultative height of all items as they are being laid out.
var itemSize: CGSize = .zero
// get number of buttonables
// get number of buttons
let totalItems = collectionView.numberOfItems(inSection: section)
//create rows
@ -190,10 +190,10 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
// create the indexPath
let indexPath = IndexPath(item: item, section: section)
// get the rect size of the buttonable
// get the rect size of the button
itemSize = delegate.collectionView(collectionView, sizeForItemAtIndexPath: indexPath)
// determine if the current buttonable will fit in the row
// determine if the current button will fit in the row
let rowItemCount = rows.last?.attributes.count ?? 0
if (layoutWidthIterator + itemSize.width) > collectionViewWidth || (rowQuantity > 0 && rowItemCount == rowQuantity) {
@ -209,26 +209,26 @@ class ButtonGroupPositionLayout: UICollectionViewLayout {
rows.append(ButtonCollectionViewRow())
}
// get the buttonable
let itemButtonable = delegate.collectionView(collectionView, buttonableAtIndexPath: indexPath)
// get the button
let itemButtonBase = delegate.collectionView(collectionView, buttonBaseAtIndexPath: indexPath)
// see if there is another item in the array
let nextItem = item + 1
// if so, get the buttonable
// if so, get the button
// and get the spacing based of the
// current buttonable and the next buttonable
// current button and the next button
if nextItem < totalItems {
//get the next buttonable
let neighbor = delegate.collectionView(collectionView, buttonableAtIndexPath: IndexPath(item: nextItem, section: section))
//get the next button
let neighbor = delegate.collectionView(collectionView, buttonBaseAtIndexPath: IndexPath(item: nextItem, section: section))
// get the spacing to go between the current and next buttonable
itemSpacing = ButtonGroupConstants.getSpacing(for: .horizontal, with: itemButtonable, neighboring: neighbor)
// get the spacing to go between the current and next button
itemSpacing = ButtonGroupConstants.getSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor)
}
// create the custom layout attribute
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, buttonable: itemButtonable, forCellWith: indexPath)
let attributes = ButtonLayoutAttributes(spacing: itemSpacing, button: itemButtonBase, forCellWith: indexPath)
attributes.frame = CGRect(x: 0, y: 0, width: itemSize.width, height: itemSize.height)
// add it to the array

View File

@ -18,7 +18,7 @@ import Combine
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
/// to its parent this object will stretch to the parent's width.
@objc(VDSTextLink)
open class TextLink: ButtonBase, Buttonable {
open class TextLink: ButtonBase {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -34,6 +34,15 @@ open class TextLink: ButtonBase, Buttonable {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
/// Enum used to describe the size.
public enum Size: String, CaseIterable {
case large
case small
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
@ -46,11 +55,9 @@ open class TextLink: ButtonBase, Buttonable {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
open var size: ButtonSize = .large { didSet { setNeedsUpdate() } }
/// The ButtonSize available.
open var size: Size = .large { didSet { setNeedsUpdate() } }
/// The ButtonSize available to this type of Buttonable.
open override var availableSizes: [ButtonSize] { [.large, .small] }
open override var textStyle: TextStyle {
size == .large ? TextStyle.bodyLarge : TextStyle.bodySmall
}
@ -66,15 +73,6 @@ open class TextLink: ButtonBase, Buttonable {
$0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted)
}
private var height: CGFloat {
switch size {
case .large:
return 44
case .small:
return 32
}
}
/// The natural size for the receiving view, considering only properties of the view itself.
open override var intrinsicContentSize: CGSize {
return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize

View File

@ -18,7 +18,7 @@ import Combine
/// you need to ensure that one of these Horizontal Contraints is not constraint of "equatTo". If you are to pin the left/right edges
/// to its parent this object will stretch to the parent's width.
@objc(VDSTextLinkCaret)
open class TextLinkCaret: ButtonBase, Buttonable {
open class TextLinkCaret: ButtonBase {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -41,14 +41,10 @@ open class TextLinkCaret: ButtonBase, Buttonable {
public enum IconPosition: String, CaseIterable {
case left, right
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private var height: CGFloat {
44
}
private var textColorConfiguration = ControlColorConfiguration().with {
$0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal)
$0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
@ -59,10 +55,7 @@ open class TextLinkCaret: ButtonBase, Buttonable {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
/// The ButtonSize available to this type of Buttonable.
public override var availableSizes: [ButtonSize] { [.large] }
//--------------------------------------------------
/// Determines icon position of Caret.
open var iconPosition: IconPosition = .right { didSet { setNeedsUpdate() } }