diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 7026c885..25074d12 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -57,20 +57,28 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Configuring the cell with default setup private func setUp() { separator.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() - contentView.addSubview(stackView) - stackView.pinToSuperView() +// contentView.addSubview(stackView) +// stackView.pinToSuperView() separator.backgroundColor = .clear } ///Updating the breadCrumbItem and UI based on the selected flag along with the surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { - separator.surface = surface - breadCrumbItem.surface = surface - stackView.addArrangedSubview(separator) - stackView.addArrangedSubview(breadCrumbItem) - stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) - separator.textColor = textColorConfiguration.getColor(surface) - separator.isHidden = hideSlash + contentView.subviews.forEach { $0.removeFromSuperview() } + contentView.addSubview(breadCrumbItem) + breadCrumbItem.pinToSuperView() + +// separator.surface = surface +// breadCrumbItem.surface = surface +// separator.removeFromSuperview() +// self.breadCrumbItem?.removeFromSuperview() +// +//// stackView.addArrangedSubview(separator) +// stackView.addArrangedSubview(breadCrumbItem) +//// stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) +// +// separator.textColor = textColorConfiguration.getColor(surface) +// separator.isHidden = hideSlash self.breadCrumbItem = breadCrumbItem layoutIfNeeded() } diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index 3b279551..952a453a 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -15,7 +15,7 @@ import Combine /// Breadcrumb contains text with a separator by default, highlights text in bold without a separator if selected. @objc (VDSBreadcrumbItem) open class BreadcrumbItem: ButtonBase { - + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -34,19 +34,38 @@ open class BreadcrumbItem: ButtonBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var hideSlash: Bool = false { didSet { setNeedsUpdate() } } + /// TextStyle used on the titleLabel. open override var textStyle: TextStyle { isSelected ? TextStyle.boldBodySmall : TextStyle.bodySmall } - + /// UIColor used on the titleLabel text. open override var textColor: UIColor { textColorConfiguration.getColor(self) } + + open override var textAttributes: [any LabelAttributeModel]? { + guard hideSlash else { return nil } + + } + + open override var text: String? { + get { hideSlash ? super.text : "/ \(super.text ?? "")"} + set { super.text = newValue } + } + /// The natural size for the receiving view, considering only properties of the view itself. /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { - return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize + guard let titleLabel else { return super.intrinsicContentSize } + // Calculate the titleLabel's intrinsic content size + let labelSize = titleLabel.sizeThatFits(CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude)) + // Adjust the size if needed (add any additional padding if your design requires) + let adjustedSize = CGSize(width: labelSize.width + contentEdgeInsets.left + contentEdgeInsets.right, + height: labelSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom) + return adjustedSize } - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 0ed7585d..78acd35f 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -15,11 +15,21 @@ import Combine @objc(VDSBreadcrumbs) open class Breadcrumbs: View { + struct BreadcrumbsSpacerConfig: ButtonGroupSpaceable { + func getSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat { + VDSLayout.Spacing.space1X.value + } + + func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat { + VDSLayout.Spacing.space1X.value + } + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- /// Array of ``BreadcrumbItem`` views for the Breadcrumbs. - open var breadcrumbs: [BreadcrumbItem] = [] { didSet { setNeedsUpdate() } } + open var breadcrumbs: [BreadcrumbItem] = [] { didSet { collectionView.buttons = breadcrumbs } } /// Array of ``BreadcurmbItemModel`` you are wanting to show. open var breadcrumbModels: [BreadcrumbItemModel] = [] { didSet { updateBreadcrumbItems() } } @@ -55,19 +65,23 @@ open class Breadcrumbs: View { $0.scrollDirection = .vertical } - ///Collectionview to render Breadcrumb Items - private lazy var collectionView: SelfSizingCollectionView = { - let collectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.isScrollEnabled = false - collectionView.translatesAutoresizingMaskIntoConstraints = false - collectionView.delegate = self - collectionView.dataSource = self - collectionView.showsHorizontalScrollIndicator = false - collectionView.showsVerticalScrollIndicator = false - collectionView.register(BreadcrumbCellItem.self, forCellWithReuseIdentifier: BreadcrumbCellItem.identifier) - collectionView.backgroundColor = .clear - return collectionView - }() +// ///Collectionview to render Breadcrumb Items +// private lazy var collectionView: SelfSizingCollectionView = { +// let collectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout) +// collectionView.isScrollEnabled = false +// collectionView.translatesAutoresizingMaskIntoConstraints = false +// collectionView.delegate = self +// collectionView.dataSource = self +// collectionView.showsHorizontalScrollIndicator = false +// collectionView.showsVerticalScrollIndicator = false +// collectionView.register(BreadcrumbCellItem.self, forCellWithReuseIdentifier: BreadcrumbCellItem.identifier) +// collectionView.backgroundColor = .clear +// return collectionView +// }() + private var collectionView = ButtonGroup().with { + $0.alignment = .left + $0.spacerConfiguration = BreadcrumbsSpacerConfig() + } //-------------------------------------------------- // MARK: - Private Methods @@ -118,22 +132,22 @@ open class Breadcrumbs: View { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - collectionView.reloadData() + collectionView.surface = surface } - open override func layoutSubviews() { - //Turn off the ability to execute updateView() in the super - //since we don't want an infinite loop - shouldUpdateView = false - super.layoutSubviews() - shouldUpdateView = true - - // Accounts for any collection size changes - DispatchQueue.main.async { [weak self] in - guard let self else { return } - self.collectionView.collectionViewLayout.invalidateLayout() - } - } +// open override func layoutSubviews() { +// //Turn off the ability to execute updateView() in the super +// //since we don't want an infinite loop +// shouldUpdateView = false +// super.layoutSubviews() +// shouldUpdateView = true +// +// // Accounts for any collection size changes +// DispatchQueue.main.async { [weak self] in +// guard let self else { return } +// self.collectionView.collectionViewLayout.invalidateLayout() +// } +// } } extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index a51371c2..e5766581 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -111,6 +111,16 @@ open class ButtonGroup: View { $0.delegate = self } + internal var spacerConfiguration: (any ButtonGroupSpaceable)? { + didSet { + if let spacerConfiguration { + positionLayout.spacerConfiguration = spacerConfiguration + } + collectionView.collectionViewLayout.invalidateLayout() + collectionView.reloadData() + } + } + /// CollectionView that renders the array of buttonBase obects. fileprivate lazy var collectionView: SelfSizingCollectionView = { diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift index 150b8928..07f852f7 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift @@ -6,21 +6,23 @@ // import Foundation +import UIKit -struct ButtonGroupConstants { - static let defaultSpace = 12.0 - - enum ButtonSpacingAxis { - case horizontal, vertical - } - +protocol ButtonGroupSpaceable { + func getSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat + func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat +} + +struct ButtonGroupSpacerConstants: ButtonGroupSpaceable { + let defaultSpace = 12.0 + /// This will determine the spacing that will go between 2 ButtonBases either horizontally or vertically /// - Parameters: /// - axis: horizontal/vertical /// - primary: first ButtonBase /// - neighboring: next ButtonBase based off of axis /// - Returns: float value - static func getSpacing(for axis: ButtonSpacingAxis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat { + func getSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat { //large button if let button = primary as? Button, button.size == .large { @@ -90,7 +92,7 @@ struct ButtonGroupConstants { /// 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] { + private func getTallestAttributes(for row: ButtonCollectionViewRow) -> [ButtonLayoutAttributes] { var height = 0.0 var foundIndexes:[Int] = [] for (index, attribute) in row.attributes.enumerated() { @@ -102,13 +104,12 @@ struct ButtonGroupConstants { return foundIndexes.compactMap { row.attributes[$0] } } - /// Gets the vertical spacing that will go between rows. /// - Parameters: /// - row: Primary row that the space will go between /// - neighboringRow: Secondary row that will be below the Primary /// - Returns: Amount of space that should live between these rows based off of the items. The largest space will win when the comparison occurs. - static func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat { + func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat { // if the neighboringRow is nil, this is the last row in the collection // so return no space guard let neighboringRow else { return 0.0 } diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift index f4ccf276..09be8cf6 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift @@ -146,6 +146,7 @@ class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{ class ButtonGroupPositionLayout: UICollectionViewLayout { weak var delegate: ButtongGroupPositionLayoutDelegate? + var spacerConfiguration: ButtonGroupSpaceable = ButtonGroupSpacerConstants() // Total height of the content. Will be used to configure the scrollview content var layoutHeight: CGFloat = 0.0 @@ -226,7 +227,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { let neighbor = delegate.collectionView(collectionView, buttonBaseAtIndexPath: IndexPath(item: nextItem, section: section)) // get the spacing to go between the current and next button - itemSpacing = ButtonGroupConstants.getSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor) + itemSpacing = spacerConfiguration.getSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor) } // create the custom layout attribute @@ -255,7 +256,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { if item > 0 { let prevRow = rows[item - 1] - rowSpacing = ButtonGroupConstants.getVerticalSpacing(for: prevRow, neighboringRow: row) + rowSpacing = spacerConfiguration.getVerticalSpacing(for: prevRow, neighboringRow: row) row.rowY = layoutHeight + rowSpacing layoutHeight += rowSpacing } @@ -273,7 +274,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { itemCache = rowAttributes } - + override func layoutAttributesForElements(in rect: CGRect)-> [UICollectionViewLayoutAttributes]? { var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []