From 090068031e8185d536d34a25005dd3ca88f74a25 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 1 Aug 2023 10:45:40 -0500 Subject: [PATCH] convert tab to control Signed-off-by: Matt Bruce --- VDS/Components/Tabs/Tab.swift | 40 +++++++++++++++++----------------- VDS/Components/Tabs/Tabs.swift | 23 ++++++------------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/VDS/Components/Tabs/Tab.swift b/VDS/Components/Tabs/Tab.swift index 1b7cda8d..753b9a8d 100644 --- a/VDS/Components/Tabs/Tab.swift +++ b/VDS/Components/Tabs/Tab.swift @@ -12,7 +12,7 @@ import Combine extension Tabs { @objc(VDSTab) - open class Tab: View { + open class Tab: Control { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -20,7 +20,7 @@ extension Tabs { open var index: Int = 0 ///label to write out the text - open var label: Label = Label() + open var label: Label = Label().with { $0.isUserInteractionEnabled = false } ///orientation of the tabs open var orientation: Tabs.Orientation = .horizontal { didSet { setNeedsUpdate() } } @@ -33,16 +33,10 @@ extension Tabs { ///Sets the Position of the Selected/Hover Border Accent for All Tabs. open var indicatorPosition: Tabs.IndicatorPosition = .bottom { didSet { setNeedsUpdate() } } - - ///An optional callback that is called when this Tab is clicked. Passes parameters (tabIndex). - open var onClick: ((Int) -> Void)? { didSet { setNeedsUpdate() } } - + ///If provided, it will set fixed width for this Tab. open var width: CGFloat? { didSet { setNeedsUpdate() } } - - ///If provided, it will set this Tab to the Active Tab on render. - open var selected: Bool = false { didSet { setNeedsUpdate() } } - + ///The text label of the tab. open var text: String = "" { didSet { setNeedsUpdate() } } @@ -71,7 +65,7 @@ extension Tabs { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var textColorConfiguration: SurfaceColorConfiguration { selected ? textColorSelectedConfiguration : textColorNonSelectedConfiguration } + private var textColorConfiguration: SurfaceColorConfiguration { isSelected ? textColorSelectedConfiguration : textColorNonSelectedConfiguration } private var textColorNonSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight , VDSColor.elementsSecondaryOnlight) private var textColorSelectedConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) private var indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteRed, VDSColor.elementsPrimaryOndark) @@ -125,7 +119,8 @@ extension Tabs { super.setup() addSubview(label) accessibilityTraits = .button - + isAccessibilityElement = true + label.translatesAutoresizingMaskIntoConstraints = false label.pinTrailing() @@ -149,16 +144,11 @@ extension Tabs { layoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), layoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), layoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) - - publisher(for: UITapGestureRecognizer()) - .sink { [weak self] _ in - guard let self else { return } - self.onClick?(self.index) - }.store(in: &subscribers) - } open override func updateView() { + super.updateView() + guard !text.isEmpty else { return } //label properties @@ -178,15 +168,25 @@ extension Tabs { setNeedsLayout() } + open override func updateAccessibility() { + super.updateAccessibility() + accessibilityLabel = text + } + open override func layoutSubviews() { super.layoutSubviews() removeBorders() - if selected { + if isSelected { addBorder(side: indicatorSide, width: indicatorWidth, color: indicatorColorConfiguration.getColor(self)) } } + + open override func accessibilityActivate() -> Bool { + sendActions(for: .touchUpInside) + return true + } } } diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index 5c7cda8c..59cfda95 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -211,20 +211,15 @@ open class Tabs: View { let tabItem = Tab() tabItem.size = size tabItem.text = model.text - tabItem.onClick = model.onClick tabItem.width = model.width tabViews.append(tabItem) tabStackView.addArrangedSubview(tabItem) - - tabItem - .publisher(for: UITapGestureRecognizer()) - .sink { [weak self] gesture in - guard let self, let tabItem = gesture.view as? Tab else { return } - if let selectedIndex = self.tabViews.firstIndex(of: tabItem) { - self.selectedIndex = selectedIndex - self.onTabChange?(selectedIndex) - } - }.store(in: &tabItem.subscribers) + tabItem.onClick = { [weak self] tab in + guard let self else { return } + model.onClick?(tab.index) + self.selectedIndex = tab.index + self.onTabChange?(tab.index) + } } setNeedsUpdate() scrollToSelectedIndex(animated: false) @@ -249,17 +244,13 @@ open class Tabs: View { // Update tab appearance based on properties for (index, tabItem) in tabViews.enumerated() { tabItem.size = size - tabItem.selected = selectedIndex == index + tabItem.isSelected = selectedIndex == index tabItem.index = index tabItem.minWidth = minWidth tabItem.textPosition = textPosition tabItem.orientation = orientation tabItem.surface = surface tabItem.indicatorPosition = indicatorPosition - tabItem.isAccessibilityElement = true - tabItem.accessibilityLabel = tabItem.text - tabItem.accessibilityHint = "Tab Item" - tabItem.accessibilityTraits = tabItem.selected ? [.button, .selected] : .button tabItem.accessibilityValue = "\(index+1) of \(tabViews.count) Tabs" }