vds_ios/VDS/Components/ListUnordered/ListUnordered.swift
2024-10-19 14:38:03 +05:30

240 lines
8.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ListUnordered.swift
// VDS
//
// Created by Vasavi Kanamarlapudi on 16/10/24.
//
import Foundation
import UIKit
import VDSCoreTokens
/// List unordered breaks up related content into distinct phrases or sentences, which improves scannability.
/// This component should be used when the text items dont need to be in numeric order.
@objcMembers
@objc(VDSListUnordered)
open class ListUnordered: View {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init() {
super.init(frame: .zero)
}
public override init(frame: CGRect) {
super.init(frame: .zero)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
/// Enum that represents the size availble for the component.
public enum Size: String, DefaultValuing, CaseIterable {
case large
case medium
case small
case micro
public static var defaultValue: Self { .large }
/// TextStyle relative to Size.
public var textStyle: TextStyle.StandardStyle {
switch self {
case .large:
return .bodyLarge
case .medium:
return .bodyMedium
case .small:
return .bodySmall
case .micro:
return .micro
}
}
}
/// Enum that represents the type of spacing available for the component.
public enum Spacing: String, CaseIterable {
case standard, compact
}
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
/// Size of the component. The default size is Large.
open var size: Size = .defaultValue { didSet { setNeedsUpdate() } }
/// Spacing type of the component.
open var spacing: Spacing = .standard { didSet { setNeedsUpdate() } }
/// Lead-in text that shows as the top text for the component. This is optional.
open var leadInText: String? = nil { didSet { setNeedsUpdate() } }
/// Array of unordered list items to show for the component.
open var unorderedList: [ListUnorderedItemModel] = [] { didSet { setNeedsUpdate() }}
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
// It can be used for Glyph level 1.
private var disc = ""
// It can be used for Glyph Level 2.
private var endash = ""
// Spacing between the list items.
private var spaceBetweenItems: CGFloat {
switch (size, spacing) {
case (.large, .standard):
return VDSLayout.space4X
case (.medium, .standard), (.small, .standard), (.micro, .standard):
return VDSLayout.space3X
case (.large, .compact):
return VDSLayout.space2X
case (.medium, .compact), (.small, .compact), (.micro, .compact):
return VDSLayout.space1X
}
}
// Padding that can be used in an item between the glyph and the item text.
private var padding: CGFloat {
switch (size, spacing) {
case (.large, .standard), (.large, .compact):
return VDSLayout.space3X
case (.medium, .standard), (.small, .standard), (.micro, .standard), (.medium, .compact), (.small, .compact), (.micro, .compact):
return VDSLayout.space2X
}
}
private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private lazy var listStackView = UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .vertical
$0.distribution = .fill
$0.spacing = spaceBetweenItems
$0.backgroundColor = .clear
}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
/// Called once when a view is initialized and is used to Setup additional UI or other constants and config.texturations.
open override func setup() {
super.setup()
// add stackview
addSubview(listStackView)
listStackView.heightGreaterThanEqualTo(constant:0)
listStackView.pinToSuperView()
}
open override func setDefaults() {
super.setDefaults()
leadInText = nil
unorderedList = []
}
/// Resets to default settings.
open override func reset() {
super.reset()
}
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
listStackView.removeArrangedSubviews()
listStackView.subviews.forEach { $0.removeFromSuperview() }
listStackView.spacing = spaceBetweenItems
if leadInText != nil {
let listItem = getListItem(with:self.leadInText, surface: surface)
listStackView.addArrangedSubview(listItem)
}
unorderedList.forEach { item in
let listItem = getListItem(levelOneText: item.levelOneText, surface: surface)
listStackView.addArrangedSubview(listItem)
item.levelTwoText?.forEach { text in
let listItem = getListItem(levelTwoText: text, surface: surface)
listStackView.addArrangedSubview(listItem)
}
}
}
//--------------------------------------------------
// MARK: - Private Methods
//--------------------------------------------------
// Get Label with the required text and text formats.
func getLabel(with text: String?, surface: Surface) -> Label {
let textLabel = Label().with {
$0.isAccessibilityElement = true
$0.lineBreakMode = .byWordWrapping
$0.text = text
$0.textStyle = size.textStyle.regular
$0.textColor = textColorConfiguration.getColor(surface)
$0.surface = surface
}
return textLabel
}
// Get the list item with the required text (LeadInText, Level 1 Text, Level 2 Text).
func getListItem(with leadInText:String? = nil, levelOneText: String? = nil, levelTwoText: String? = nil, surface:Surface) -> UIView {
let itemStackView = UIStackView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .horizontal
$0.alignment = .leading
$0.distribution = .fill
$0.spacing = padding
$0.backgroundColor = .clear
}
// StackView with LeadIntext if provided.
if leadInText != nil {
let leadTextLabel = getLabel(with: leadInText, surface: surface)
itemStackView.addArrangedSubview(leadTextLabel)
}
// StackView with Level 1 Text if provided.
if levelOneText != nil {
// Add level 1 glyph: 'disc, bold'
let discLabel = getLabel(with: disc, surface: surface)
discLabel.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
itemStackView.addArrangedSubview(discLabel)
// Add level 1 Text
let levelOneLabel = getLabel(with: levelOneText, surface: surface)
itemStackView.addArrangedSubview(levelOneLabel)
}
// StackView with Level 2 Text if provided.
if levelTwoText != nil {
// Set level 2 leading space as needed for alignment.
let discSpaceView = View()
let discLabel = getLabel(with: disc, surface: surface)
discSpaceView.widthAnchor.constraint(equalToConstant: discLabel.intrinsicContentSize.width).activate()
itemStackView.addArrangedSubview(discSpaceView)
// Add level 2 glyph: 'en dash, regular'
let endashLabel = getLabel(with: endash, surface: surface)
endashLabel.widthAnchor.constraint(equalToConstant: endashLabel.intrinsicContentSize.width).activate()
itemStackView.addArrangedSubview(endashLabel)
// Add level 2 Text
let levelTwoLabel = getLabel(with: levelTwoText, surface: surface)
itemStackView.addArrangedSubview(levelTwoLabel)
}
return itemStackView
}
}