diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 7c65a8b0..40a96b5a 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -23,9 +23,9 @@ 710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */; }; + 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; - 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */; }; 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86D92B96F44C00700965 /* PaginationButton.swift */; }; @@ -165,7 +165,6 @@ EAEEECAF2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */; }; EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; }; - EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */; }; EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* CheckboxItem.swift */; }; EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; }; EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09F289AB7EC00B287F5 /* View.swift */; }; @@ -211,9 +210,9 @@ 710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = ""; }; + 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; - 71ACE89D2BA1CC1700FB6ADC /* TiletEyebrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiletEyebrowModel.swift; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; 71FC86D92B96F44C00700965 /* PaginationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationButton.swift; sourceTree = ""; }; @@ -355,7 +354,6 @@ EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ToggleViewChangeLog.txt; sourceTree = ""; }; EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = ""; }; - EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsFlowLayout.swift; sourceTree = ""; }; EAF7F0932899861000B287F5 /* CheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxItem.swift; sourceTree = ""; }; EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = ""; }; EAF7F09F289AB7EC00B287F5 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; @@ -400,7 +398,6 @@ isa = PBXGroup; children = ( 18A65A012B96E848006602CC /* Breadcrumbs.swift */, - EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */, 18A65A032B96F050006602CC /* BreadcrumbItem.swift */, 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */, 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */, @@ -1139,7 +1136,6 @@ 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, - EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */, diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 9f0ea68b..bd04304c 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -24,6 +24,8 @@ final class BreadcrumbCellItem: UICollectionViewCell { $0.distribution = .fill $0.alignment = .fill $0.spacing = VDSLayout.Spacing.space1X.value + $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) + $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) } }() @@ -64,13 +66,14 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Updating the breadCrumbItem and UI based on the selected flag along with the surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { - //remove views from stack - separator.removeFromSuperview() - self.breadCrumbItem?.removeFromSuperview() - //update surface separator.surface = surface breadCrumbItem.surface = surface + breadCrumbItem.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + breadCrumbItem.setContentHuggingPriority(.defaultLow, for: .horizontal) + + //remove previous views + stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } //add to stack stackView.addArrangedSubview(separator) @@ -80,15 +83,8 @@ final class BreadcrumbCellItem: UICollectionViewCell { //update separator separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash - self.breadCrumbItem = breadCrumbItem layoutIfNeeded() } - - /// Remove views from StackView. - override func prepareForReuse() { - super.prepareForReuse() - separator.removeFromSuperview() - breadCrumbItem?.removeFromSuperview() - } } + diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index 3b279551..d549dd9a 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -44,9 +44,15 @@ open class BreadcrumbItem: ButtonBase { /// 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 //-------------------------------------------------- @@ -64,8 +70,8 @@ open class BreadcrumbItem: ButtonBase { open override func setup() { super.setup() isAccessibilityElement = true - accessibilityTraits = .button - accessibilityLabel = "Breadcrumb" + accessibilityTraits = .link + contentHorizontalAlignment = .leading } /// Used to make changes to the View based off a change events or from local properties. @@ -86,4 +92,11 @@ open class BreadcrumbItem: ButtonBase { shouldUpdateView = true setNeedsUpdate() } + + /// Used to update any Accessibility properties. + open override func updateAccessibility() { + super.updateAccessibility() + accessibilityLabel = "Breadcrumb \(text ?? "")" + } + } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 0ed7585d..2dd14d18 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -47,14 +47,17 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - let layout: UICollectionViewFlowLayout = BreadcrumbsFlowLayout().with { - $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize - $0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value - $0.minimumLineSpacing = VDSLayout.Spacing.space1X.value - $0.sectionInset = .zero - $0.scrollDirection = .vertical + fileprivate lazy var layout = ButtonGroupPositionLayout().with { + $0.position = .left + $0.delegate = self + $0.axisSpacer = { _, _, _ in + return VDSLayout.Spacing.space1X.value + } + $0.verticalSpacer = { _, _ in + return VDSLayout.Spacing.space1X.value + } } - + ///Collectionview to render Breadcrumb Items private lazy var collectionView: SelfSizingCollectionView = { let collectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout) @@ -134,9 +137,10 @@ open class Breadcrumbs: View { self.collectionView.collectionViewLayout.invalidateLayout() } } + private var separatorWidth = Label().with { $0.text = "/"; $0.sizeToFit() }.intrinsicContentSize.width } -extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { +extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, ButtongGroupPositionLayoutDelegate { //-------------------------------------------------- // MARK: - UICollectionView Delegate & Datasource //-------------------------------------------------- @@ -150,5 +154,16 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbs[indexPath.row]) return cell } - + + public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { + let breadcrumb = breadcrumbs[indexPath.row] + let intrinsicSize = breadcrumb.intrinsicContentSize + let separatorFullWidth: CGFloat = indexPath.row == 0 ? 0 : VDSLayout.Spacing.space1X.value + separatorWidth + let cellwidth = intrinsicSize.width + separatorFullWidth + return .init(width: min(cellwidth, collectionView.frame.width), height: intrinsicSize.height) + } + + public func collectionView(_ collectionView: UICollectionView, buttonBaseAtIndexPath indexPath: IndexPath) -> ButtonBase { + breadcrumbs[indexPath.row] + } } diff --git a/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift b/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift deleted file mode 100644 index d6daf151..00000000 --- a/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// BreadcrumsFlowLayout.swift -// VDS -// -// Created by Matt Bruce on 3/21/24. -// - -import Foundation -import UIKit - -class BreadcrumbsFlowLayout: UICollectionViewFlowLayout { - - override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - let attributes = super.layoutAttributesForElements(in: rect) - - var leftMargin = sectionInset.left - var maxY: CGFloat = -1.0 - attributes?.forEach { layoutAttribute in - if layoutAttribute.frame.origin.y >= maxY { - leftMargin = sectionInset.left - } - - layoutAttribute.frame.origin.x = leftMargin - - leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing - maxY = max(layoutAttribute.frame.maxY , maxY) - } - - return attributes - } -} diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift index 150b8928..3e02465c 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupConstants.swift @@ -6,21 +6,18 @@ // import Foundation +import UIKit struct ButtonGroupConstants { static let defaultSpace = 12.0 - enum ButtonSpacingAxis { - case horizontal, vertical - } - /// 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 { + static func getSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat { //large button if let button = primary as? Button, button.size == .large { diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift index f4ccf276..5d3a339f 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift @@ -146,6 +146,8 @@ class ButtonLayoutAttributes: UICollectionViewLayoutAttributes{ class ButtonGroupPositionLayout: UICollectionViewLayout { weak var delegate: ButtongGroupPositionLayoutDelegate? + var verticalSpacer: ((ButtonCollectionViewRow, ButtonCollectionViewRow?) -> CGFloat)? + var axisSpacer: ((NSLayoutConstraint.Axis, ButtonBase, ButtonBase) -> CGFloat)? // Total height of the content. Will be used to configure the scrollview content var layoutHeight: CGFloat = 0.0 @@ -154,7 +156,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { var buttonPercentage: CGFloat? private var itemCache: [ButtonLayoutAttributes] = [] - + override func prepare() { super.prepare() @@ -226,7 +228,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 = getAxisSpacing(for: .horizontal, with: itemButtonBase, neighboring: neighbor) } // create the custom layout attribute @@ -255,7 +257,7 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { if item > 0 { let prevRow = rows[item - 1] - rowSpacing = ButtonGroupConstants.getVerticalSpacing(for: prevRow, neighboringRow: row) + rowSpacing = getVerticalSpacing(for: prevRow, neighboringRow: row) row.rowY = layoutHeight + rowSpacing layoutHeight += rowSpacing } @@ -300,5 +302,19 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { } return collectionView.bounds.width } + + private func getAxisSpacing(for axis: NSLayoutConstraint.Axis, with primary: ButtonBase, neighboring: ButtonBase) -> CGFloat { + guard let axisSpacer else { + return ButtonGroupConstants.getSpacing(for: axis, with: primary, neighboring: neighboring) + } + return axisSpacer(axis, primary, neighboring) + } + + private func getVerticalSpacing(for row: ButtonCollectionViewRow, neighboringRow: ButtonCollectionViewRow?) -> CGFloat { + guard let verticalSpacer else { + return ButtonGroupConstants.getVerticalSpacing(for: row, neighboringRow: neighboringRow) + } + return verticalSpacer(row, neighboringRow) + } }