From 7667908ffdbf06254461b253bd6c8fd4211682cf Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Wed, 21 Aug 2024 18:32:40 +0530 Subject: [PATCH 01/13] Digital ACT-191 ONEAPP-10586 story: added new file for footnote --- VDS.xcodeproj/project.pbxproj | 16 ++++++ VDS/Components/Footnote/Footnote.swift | 56 +++++++++++++++++++ VDS/Components/Footnote/FootnoteChangeLog.txt | 17 ++++++ VDS/VDS.docc/VDS.md | 1 + 4 files changed, 90 insertions(+) create mode 100644 VDS/Components/Footnote/Footnote.swift create mode 100644 VDS/Components/Footnote/FootnoteChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 3e5d50bc..dd2613d1 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ 1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; }; 186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; + 18926F5B2C7616A500C55BF6 /* Footnote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18926F5A2C7616A500C55BF6 /* Footnote.swift */; }; + 18926F5D2C7616C600C55BF6 /* FootnoteChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */; }; 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; @@ -227,6 +229,8 @@ 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = ""; }; 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; + 18926F5A2C7616A500C55BF6 /* Footnote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Footnote.swift; sourceTree = ""; }; + 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = FootnoteChangeLog.txt; sourceTree = ""; }; 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; @@ -494,6 +498,15 @@ path = DropdownSelect; sourceTree = ""; }; + 18926F592C76168300C55BF6 /* Footnote */ = { + isa = PBXGroup; + children = ( + 18926F5A2C7616A500C55BF6 /* Footnote.swift */, + 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */, + ); + path = Footnote; + sourceTree = ""; + }; 18A3F1202BD8F5DE00498E4A /* Calendar */ = { isa = PBXGroup; children = ( @@ -706,6 +719,7 @@ EAF7F092289985E200B287F5 /* Checkbox */, EAC58C1F2BF127F000BA39FA /* DatePicker */, 186D13C92BBA8A3500986B53 /* DropdownSelect */, + 18926F592C76168300C55BF6 /* Footnote */, EA985BF3296C609E00F2FF2E /* Icon */, 180636C52C29B06200C92D86 /* InputStepper */, EA3362412892EF700071C351 /* Label */, @@ -1212,6 +1226,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 18926F5D2C7616C600C55BF6 /* FootnoteChangeLog.txt in Resources */, EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */, 184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */, EA3362072891E14D0071C351 /* VerizonNHGeDS-Regular.otf in Resources */, @@ -1306,6 +1321,7 @@ 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */, EAF2F4762C231EAA007BFEDC /* AccessibilityActionElement.swift in Sources */, EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */, + 18926F5B2C7616A500C55BF6 /* Footnote.swift in Sources */, EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAF193422C134F3400C68D18 /* Table.swift in Sources */, diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift new file mode 100644 index 00000000..9522cc9a --- /dev/null +++ b/VDS/Components/Footnote/Footnote.swift @@ -0,0 +1,56 @@ +// +// Footnote.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 21/08/24. +// + +import Foundation +import UIKit +import VDSCoreTokens +import Combine + +/// A footnote is text that provides supporting details, legal copy and links to related content. If exists at the bottom or "foot" of a page or section. +@objcMembers +@objc(VDSFootnote) +open class Footnote: 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: - Overrides + //-------------------------------------------------- + + /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. + open override func setup() { + super.setup() + + } + + open override func setDefaults() { + super.setDefaults() + } + + /// 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() + } +} diff --git a/VDS/Components/Footnote/FootnoteChangeLog.txt b/VDS/Components/Footnote/FootnoteChangeLog.txt new file mode 100644 index 00000000..5dce6539 --- /dev/null +++ b/VDS/Components/Footnote/FootnoteChangeLog.txt @@ -0,0 +1,17 @@ +MM/DD/YYYY +---------------- +Initial Brand 3.0 handoff + +12/18/2023 +---------------- +- New + +12/28/2023 +---------------- +- hideSymbol updated to showSymbol and default set to True. +- Figma-only properties section added in Footnote Item Configurations section. + +01/16/2024 +---------------- +- hideSymbol reverted to hideSymbol and default set to False. +- Figma-only properties section removed. diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index 0a494234..fd139f95 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -32,6 +32,7 @@ Using the system allows designers and developers to collaborate more easily and - ``CheckboxItem`` - ``CheckboxGroup`` - ``DropdownSelect`` +- ``Footnote`` - ``Icon`` - ``InputStepper`` - ``InputField`` From 9cbfe1d46a278721a6efafc79d10cabbf67d67f6 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Thu, 22 Aug 2024 17:08:12 +0530 Subject: [PATCH 02/13] Digital ACT-191 ONEAPP-10586 story: added public properties --- VDS/Components/Footnote/Footnote.swift | 145 +++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 9522cc9a..553dda5d 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -29,7 +29,142 @@ open class Footnote: View { public required init?(coder: NSCoder) { super.init(coder: coder) } + + //-------------------------------------------------- + // MARK: - enums + //-------------------------------------------------- + /// Enum used to describe the kind of component. + public enum Kind: String, DefaultValuing, CaseIterable { + case primary, secondary + + /// The default kind is 'primary'. + public static var defaultValue : Self { .secondary } + + /// Color configuation to Symbol and Text relative to kind. + public var colorConfiguration: SurfaceColorConfiguration { + switch self { + case .primary: + return SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + case .secondary: + return SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + } + } + } + /// Enum that represents the size availble for component. + public enum Size: String, DefaultValuing, CaseIterable { + case micro + case small + case large + + public static var defaultValue: Self { .micro } + + /// TextStyle relative to Size. + public var textStyle: TextStyle.StandardStyle { + switch self { + case .micro: + return .micro + case .small: + return .bodySmall + case .large: + return .bodyLarge + } + } + } + + /// Enum used to describe the symboldType of component. + public enum SymbolType: String, DefaultValuing, CaseIterable { + case asterisk + case doubleAsterisk + case character + + public static var defaultValue: Self { .asterisk } + + /// TextStyle relative to Size. + public var text: String { + switch self { + case .asterisk: + return "*" + case .doubleAsterisk: + return "**" + case .character: + return "1." + } + } + } + + /// Enum used to describe the width of a fixed value or percentage of parent's width. + public enum Width { + case percentage(CGFloat) + case value(CGFloat) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// Color to the component. The default kind is Secondary. + open var kind: Kind = .defaultValue { didSet { setNeedsUpdate() } } + + /// Size of the component. The default size is Micro. + open var size: Size = .defaultValue { didSet { setNeedsUpdate() } } + + /// If hideSymbol true, the component will show text without symbol. + open var hideSymbol: Bool = false { didSet { setNeedsUpdate() } } + + /// Size of the component. The default size is Micro. + open var symbolType: SymbolType = .defaultValue { didSet { setNeedsUpdate() } } + + /// Text of the footnote item. + open var text: String? { didSet { setNeedsUpdate() } } + + /// Any percentage or pixel value and cannot exceed container size.. + /// If there is a width that is larger than container size, the footnote will resize to container's width. + open var width: Width? { + get { _width } + set { + if let newValue { + switch newValue { + case .percentage(let percentage): + if percentage <= 100.0 { + _width = newValue + } + case .value(let value): + if value > 0 { + _width = newValue + } + } + } else { + _width = nil + } + setNeedsUpdate() + } + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var _width: Width? = nil + + internal var footnoteItem = UIStackView().with { + $0.axis = .horizontal + $0.spacing = VDSLayout.space1X + $0.alignment = .top + $0.distribution = .fillEqually + } + + internal var symbolLabel = Label().with { + $0.isAccessibilityElement = true + } + + internal var footnoteItemLabel = Label().with { + $0.isAccessibilityElement = true + $0.lineBreakMode = .byWordWrapping + } + + //-------------------------------------------------- + // MARK: - Configuration Properties + //-------------------------------------------------- + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -38,6 +173,12 @@ open class Footnote: View { open override func setup() { super.setup() + addSubview(symbolLabel) + symbolLabel.pinToSuperView() + + addSubview(footnoteItemLabel) + footnoteItemLabel.pinToSuperView() + } open override func setDefaults() { @@ -52,5 +193,9 @@ open class Footnote: View { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() + symbolLabel.text = hideSymbol ? "" : symbolType.text + footnoteItemLabel.text = text + symbolLabel.surface = surface + footnoteItemLabel.surface = surface } } From 73caedce5fe4817e30a5a6db31b68793e35d7c88 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Thu, 29 Aug 2024 19:09:22 +0530 Subject: [PATCH 03/13] Digital ACT-191 ONEAPP-10586 story: updating content as per configuration --- VDS/Components/Footnote/Footnote.swift | 80 +++++++++++++++++++------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 553dda5d..0771333c 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -10,7 +10,8 @@ import UIKit import VDSCoreTokens import Combine -/// A footnote is text that provides supporting details, legal copy and links to related content. If exists at the bottom or "foot" of a page or section. +/// A footnote is text that provides supporting details, legal copy and links to related content. +/// It exists at the bottom or "foot" of a page or section. @objcMembers @objc(VDSFootnote) open class Footnote: View { @@ -29,7 +30,7 @@ open class Footnote: View { public required init?(coder: NSCoder) { super.init(coder: coder) } - + //-------------------------------------------------- // MARK: - enums //-------------------------------------------------- @@ -98,25 +99,27 @@ open class Footnote: View { case percentage(CGFloat) case value(CGFloat) } - + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- /// Color to the component. The default kind is Secondary. open var kind: Kind = .defaultValue { didSet { setNeedsUpdate() } } - + /// Size of the component. The default size is Micro. open var size: Size = .defaultValue { didSet { setNeedsUpdate() } } - + /// If hideSymbol true, the component will show text without symbol. open var hideSymbol: Bool = false { didSet { setNeedsUpdate() } } - + /// Size of the component. The default size is Micro. open var symbolType: SymbolType = .defaultValue { didSet { setNeedsUpdate() } } - + /// Text of the footnote item. open var text: String? { didSet { setNeedsUpdate() } } + open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } } + /// Any percentage or pixel value and cannot exceed container size.. /// If there is a width that is larger than container size, the footnote will resize to container's width. open var width: Width? { @@ -144,27 +147,32 @@ open class Footnote: View { // MARK: - Private Properties //-------------------------------------------------- private var _width: Width? = nil - - internal var footnoteItem = UIStackView().with { + + private lazy var itemStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal - $0.spacing = VDSLayout.space1X $0.alignment = .top - $0.distribution = .fillEqually + $0.distribution = .fill + $0.spacing = VDSLayout.space1X + $0.backgroundColor = .clear } internal var symbolLabel = Label().with { $0.isAccessibilityElement = true + $0.numberOfLines = 1 + $0.sizeToFit() } - internal var footnoteItemLabel = Label().with { + internal var textLabel = Label().with { $0.isAccessibilityElement = true $0.lineBreakMode = .byWordWrapping } //-------------------------------------------------- - // MARK: - Configuration Properties + // MARK: - Constraints //-------------------------------------------------- - + internal var symbolWidthConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -173,29 +181,61 @@ open class Footnote: View { open override func setup() { super.setup() - addSubview(symbolLabel) - symbolLabel.pinToSuperView() + // add footnote item stackview. + addSubview(itemStackView) + itemStackView.pinToSuperView() + + // add symbol label, text label to stack. + itemStackView.addArrangedSubview(symbolLabel) + itemStackView.addArrangedSubview(textLabel) + itemStackView.setCustomSpacing(VDSLayout.space1X, after: symbolLabel) - addSubview(footnoteItemLabel) - footnoteItemLabel.pinToSuperView() + symbolWidthConstraint = symbolLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) + symbolWidthConstraint?.isActive = true } open override func setDefaults() { super.setDefaults() + hideSymbol = false + text = nil + tooltipModel = nil + width = nil } /// Resets to default settings. open override func reset() { + symbolLabel.reset() + textLabel.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() + + // Update symbolLabel + symbolWidthConstraint?.isActive = false symbolLabel.text = hideSymbol ? "" : symbolType.text - footnoteItemLabel.text = text + symbolLabel.textColor = kind.colorConfiguration.getColor(self) + symbolLabel.textStyle = size.textStyle.regular symbolLabel.surface = surface - footnoteItemLabel.surface = surface + + // Update symbolLabel width as per updated text size + symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolLabel.intrinsicContentSize.width) + symbolWidthConstraint?.isActive = true + + // Update textLabel + textLabel.text = text + textLabel.textColor = kind.colorConfiguration.getColor(self) + textLabel.textStyle = size.textStyle.regular + textLabel.surface = surface + + // Set the textLabel attributes + if let tooltipModel { + var attributes: [any LabelAttributeModel] = [] + attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self)) + textLabel.attributes = attributes + } } } From a0b139b0af09d6f14b3a0e18a9734aa377e07619 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 2 Sep 2024 11:33:59 +0530 Subject: [PATCH 04/13] Digital ACT-191 ONEAPP-10586 story: added footnote group and updating with footnote items --- VDS.xcodeproj/project.pbxproj | 4 + VDS/Components/Footnote/Footnote.swift | 63 ++++++- VDS/Components/Footnote/FootnoteGroup.swift | 180 ++++++++++++++++++++ VDS/VDS.docc/VDS.md | 1 + 4 files changed, 241 insertions(+), 7 deletions(-) create mode 100644 VDS/Components/Footnote/FootnoteGroup.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index dd2613d1..e0ea031a 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; }; 1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; }; 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; + 183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */; }; 184023452C61E7AD00A412C8 /* PriceLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184023442C61E7AD00A412C8 /* PriceLockup.swift */; }; 184023472C61E7EC00A412C8 /* PriceLockupChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */; }; 1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; }; @@ -218,6 +219,7 @@ 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = ""; }; 1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = ""; }; 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = ""; }; + 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteGroup.swift; sourceTree = ""; }; 184023442C61E7AD00A412C8 /* PriceLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLockup.swift; sourceTree = ""; }; 184023462C61E7EC00A412C8 /* PriceLockupChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PriceLockupChangeLog.txt; sourceTree = ""; }; 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateViewCell.swift; sourceTree = ""; }; @@ -502,6 +504,7 @@ isa = PBXGroup; children = ( 18926F5A2C7616A500C55BF6 /* Footnote.swift */, + 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */, 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */, ); path = Footnote; @@ -1291,6 +1294,7 @@ EA3361C328902D960071C351 /* Toggle.swift in Sources */, EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */, EAC58C232BF2824200BA39FA /* DatePicker.swift in Sources */, + 183B16F72C80B32200BA6A10 /* FootnoteGroup.swift in Sources */, EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */, 71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */, EAC9258C2911C9DE00091998 /* InputField.swift in Sources */, diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 0771333c..0d1575f0 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -8,7 +8,6 @@ import Foundation import UIKit import VDSCoreTokens -import Combine /// A footnote is text that provides supporting details, legal copy and links to related content. /// It exists at the bottom or "foot" of a page or section. @@ -120,7 +119,7 @@ open class Footnote: View { open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } } - /// Any percentage or pixel value and cannot exceed container size.. + /// Any percentage or pixel value and cannot exceed container size. /// If there is a width that is larger than container size, the footnote will resize to container's width. open var width: Width? { get { _width } @@ -143,6 +142,9 @@ open class Footnote: View { } } + /// To set the widest symbol width from the symbol container in the group. + open var symbolWiderWidth: CGFloat = 0 { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -167,12 +169,22 @@ open class Footnote: View { $0.isAccessibilityElement = true $0.lineBreakMode = .byWordWrapping } + + //-------------------------------------------------- + // MARK: - Configuration Properties + //-------------------------------------------------- + internal var maxWidth: CGFloat { frame.size.width } + internal var minWidth: CGFloat { containerSize.width } + internal var containerSize: CGSize { CGSize(width: 45, height: 44) } //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- internal var symbolWidthConstraint: NSLayoutConstraint? - + internal var itemWidthConstraint: NSLayoutConstraint? + internal var trailingEqualsConstraint: NSLayoutConstraint? + internal var trailingLessThanEqualsConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -183,7 +195,12 @@ open class Footnote: View { // add footnote item stackview. addSubview(itemStackView) - itemStackView.pinToSuperView() + itemStackView.pinTop().pinBottom().pinLeading() + trailingEqualsConstraint = itemStackView.pinTrailing(anchor: trailingAnchor) + + // width constraints + itemWidthConstraint = itemStackView.widthAnchor.constraint(equalToConstant: 0).deactivate() + trailingLessThanEqualsConstraint = itemStackView.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate() // add symbol label, text label to stack. itemStackView.addArrangedSubview(symbolLabel) @@ -192,7 +209,6 @@ open class Footnote: View { symbolWidthConstraint = symbolLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) symbolWidthConstraint?.isActive = true - } open override func setDefaults() { @@ -221,8 +237,13 @@ open class Footnote: View { symbolLabel.textStyle = size.textStyle.regular symbolLabel.surface = surface - // Update symbolLabel width as per updated text size - symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolLabel.intrinsicContentSize.width) + //Set width to the symbol label + if symbolWiderWidth > 0 { + // Set the widest symbol width from the symbol container in the group. + symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolWiderWidth) + } else { + symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolLabel.intrinsicContentSize.width) + } symbolWidthConstraint?.isActive = true // Update textLabel @@ -237,5 +258,33 @@ open class Footnote: View { attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self)) textLabel.attributes = attributes } + + updateContainerWidth() + } + + /// Update container width after updating content. + internal func updateContainerWidth() { + var newWidth = 0.0 + switch width { + case .percentage(let percentage): + newWidth = max(maxWidth * ((percentage) / 100), minWidth) + + case .value(let value): + newWidth = value > maxWidth ? maxWidth : value + + case nil: + newWidth = maxWidth + } + itemWidthConstraint?.deactivate() + trailingLessThanEqualsConstraint?.deactivate() + trailingEqualsConstraint?.deactivate() + + if newWidth > minWidth && newWidth < maxWidth { + itemWidthConstraint?.constant = newWidth + itemWidthConstraint?.activate() + trailingLessThanEqualsConstraint?.activate() + } else { + trailingEqualsConstraint?.activate() + } } } diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift new file mode 100644 index 00000000..755ed9aa --- /dev/null +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -0,0 +1,180 @@ +// +// FootnoteGroup.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 29/08/24. +// + +import Foundation +import UIKit +import VDSCoreTokens + +/// This must always be paired with one or more ``Footnote`` in a FootnoteGroup. +@objcMembers +@objc(VDSFootnoteGroup) +open class FootnoteGroup: 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 used to describe the width of a fixed value or percentage of parent's width. + public enum Width { + case percentage(CGFloat) + case value(CGFloat) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// Array of ``Footnote`` for the Footnote items. + open var footnoteitems: [Footnote] = [] { didSet { setNeedsUpdate() } } + + /// Any percentage or pixel value and cannot exceed container size. + /// If there is a width that is larger than container size, the footnote will resize to container's width. + open var width: Width? { + get { _width } + set { + if let newValue { + switch newValue { + case .percentage(let percentage): + if percentage <= 100.0 { + _width = newValue + } + case .value(let value): + if value > 0 { + _width = newValue + } + } + } else { + _width = nil + } + setNeedsUpdate() + } + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var _width: Width? = nil + + private lazy var stackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .vertical + $0.alignment = .top + $0.distribution = .fill + $0.spacing = VDSLayout.space3X + $0.backgroundColor = .clear + } + + //-------------------------------------------------- + // MARK: - Configuration Properties + //-------------------------------------------------- + internal var maxWidth: CGFloat { frame.size.width } + internal var minWidth: CGFloat { containerSize.width } + internal var containerSize: CGSize { CGSize(width: 55, height: 44) } + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + internal var widthConstraint: NSLayoutConstraint? + internal var trailingEqualsConstraint: NSLayoutConstraint? + internal var trailingLessThanEqualsConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + + /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. + open override func setup() { + super.setup() + + // add footnote item stackview. + addSubview(stackView) + stackView.pinTop().pinBottom().pinLeading() + trailingEqualsConstraint = stackView.pinTrailing(anchor: trailingAnchor) + + // width constraints + trailingLessThanEqualsConstraint = stackView.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate() + widthConstraint = stackView.widthAnchor.constraint(equalToConstant: 0).deactivate() + } + + open override func setDefaults() { + super.setDefaults() + width = nil + footnoteitems = [] + } + + /// 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() + updateContainerWidth() + + // symbol containers are as wide as the widest symbol container in the group. + var symbolMaxWidth = 0.0 + if footnoteitems.count > 0 { + for index in 0...footnoteitems.count - 1 { + let footnote: Footnote = footnoteitems[index] + let separatorWidth = Label().with { $0.text = footnote.symbolType.text; $0.sizeToFit() }.intrinsicContentSize.width + symbolMaxWidth = separatorWidth > symbolMaxWidth ? separatorWidth : symbolMaxWidth + } + } + + stackView.subviews.forEach{$0.removeFromSuperview()} + // add symbol label, text label to stack. + if footnoteitems.count > 0 { + for index in 0...footnoteitems.count - 1 { + let footnote: Footnote = footnoteitems[index] + footnote.symbolWiderWidth = symbolMaxWidth + footnote.surface = surface + stackView.addArrangedSubview(footnote) + } + } + } + + /// Update container width after updating content. + internal func updateContainerWidth() { + var newWidth = 0.0 + switch width { + case .percentage(let percentage): + newWidth = max(maxWidth * ((percentage) / 100), minWidth) + + case .value(let value): + newWidth = value > maxWidth ? maxWidth : value + + case nil: + newWidth = maxWidth + } + + widthConstraint?.deactivate() + trailingLessThanEqualsConstraint?.deactivate() + trailingEqualsConstraint?.deactivate() + + if newWidth > minWidth && newWidth < maxWidth { + widthConstraint?.constant = newWidth + widthConstraint?.activate() + trailingLessThanEqualsConstraint?.activate() + } else { + trailingEqualsConstraint?.activate() + } + } +} diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index fd139f95..d1afd2b1 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -33,6 +33,7 @@ Using the system allows designers and developers to collaborate more easily and - ``CheckboxGroup`` - ``DropdownSelect`` - ``Footnote`` +- ``FootnoteGroup`` - ``Icon`` - ``InputStepper`` - ``InputField`` From 09351db136475267e2eef9ec0651d7b73db8a5e8 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Thu, 12 Sep 2024 13:26:06 +0530 Subject: [PATCH 05/13] Digital ACT-191 ONEAPP-10586 story: updated symbolType to use as String, camelCase applied to footnoteItems --- VDS/Components/Footnote/Footnote.swift | 27 +++------------------ VDS/Components/Footnote/FootnoteGroup.swift | 18 +++++++------- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 0d1575f0..8583a05b 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -72,27 +72,6 @@ open class Footnote: View { } } - /// Enum used to describe the symboldType of component. - public enum SymbolType: String, DefaultValuing, CaseIterable { - case asterisk - case doubleAsterisk - case character - - public static var defaultValue: Self { .asterisk } - - /// TextStyle relative to Size. - public var text: String { - switch self { - case .asterisk: - return "*" - case .doubleAsterisk: - return "**" - case .character: - return "1." - } - } - } - /// Enum used to describe the width of a fixed value or percentage of parent's width. public enum Width { case percentage(CGFloat) @@ -111,8 +90,8 @@ open class Footnote: View { /// If hideSymbol true, the component will show text without symbol. open var hideSymbol: Bool = false { didSet { setNeedsUpdate() } } - /// Size of the component. The default size is Micro. - open var symbolType: SymbolType = .defaultValue { didSet { setNeedsUpdate() } } + /// symbol type will be shown for the footnote item. The default symbolType is 'asterisk'. + open var symbolType: String = "*" { didSet { setNeedsUpdate() } } /// Text of the footnote item. open var text: String? { didSet { setNeedsUpdate() } } @@ -232,7 +211,7 @@ open class Footnote: View { // Update symbolLabel symbolWidthConstraint?.isActive = false - symbolLabel.text = hideSymbol ? "" : symbolType.text + symbolLabel.text = hideSymbol ? "" : symbolType symbolLabel.textColor = kind.colorConfiguration.getColor(self) symbolLabel.textStyle = size.textStyle.regular symbolLabel.surface = surface diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift index 755ed9aa..0f229ac8 100644 --- a/VDS/Components/Footnote/FootnoteGroup.swift +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -42,7 +42,7 @@ open class FootnoteGroup: View { // MARK: - Public Properties //-------------------------------------------------- /// Array of ``Footnote`` for the Footnote items. - open var footnoteitems: [Footnote] = [] { didSet { setNeedsUpdate() } } + open var footnoteItems: [Footnote] = [] { didSet { setNeedsUpdate() } } /// Any percentage or pixel value and cannot exceed container size. /// If there is a width that is larger than container size, the footnote will resize to container's width. @@ -116,7 +116,7 @@ open class FootnoteGroup: View { open override func setDefaults() { super.setDefaults() width = nil - footnoteitems = [] + footnoteItems = [] } /// Resets to default settings. @@ -131,19 +131,19 @@ open class FootnoteGroup: View { // symbol containers are as wide as the widest symbol container in the group. var symbolMaxWidth = 0.0 - if footnoteitems.count > 0 { - for index in 0...footnoteitems.count - 1 { - let footnote: Footnote = footnoteitems[index] - let separatorWidth = Label().with { $0.text = footnote.symbolType.text; $0.sizeToFit() }.intrinsicContentSize.width + if footnoteItems.count > 0 { + for index in 0...footnoteItems.count - 1 { + let footnote: Footnote = footnoteItems[index] + let separatorWidth = Label().with { $0.text = footnote.symbolType; $0.sizeToFit() }.intrinsicContentSize.width symbolMaxWidth = separatorWidth > symbolMaxWidth ? separatorWidth : symbolMaxWidth } } stackView.subviews.forEach{$0.removeFromSuperview()} // add symbol label, text label to stack. - if footnoteitems.count > 0 { - for index in 0...footnoteitems.count - 1 { - let footnote: Footnote = footnoteitems[index] + if footnoteItems.count > 0 { + for index in 0...footnoteItems.count - 1 { + let footnote: Footnote = footnoteItems[index] footnote.symbolWiderWidth = symbolMaxWidth footnote.surface = surface stackView.addArrangedSubview(footnote) From 9b885da7ca4d3010bfa97740aa556ada9ee47a28 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Thu, 12 Sep 2024 15:46:32 +0530 Subject: [PATCH 06/13] using .isHidden feature --- VDS/Components/Footnote/Footnote.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 8583a05b..4d352e7b 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -211,7 +211,8 @@ open class Footnote: View { // Update symbolLabel symbolWidthConstraint?.isActive = false - symbolLabel.text = hideSymbol ? "" : symbolType + symbolLabel.text = symbolType + symbolLabel.isHidden = hideSymbol symbolLabel.textColor = kind.colorConfiguration.getColor(self) symbolLabel.textStyle = size.textStyle.regular symbolLabel.surface = surface From e08de8fb3eebb732d98644f5779a25c30df992a4 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Thu, 12 Sep 2024 18:26:21 +0530 Subject: [PATCH 07/13] Digital ACT-191 ONEAPP-10586 story: alignment changes to stackview --- VDS/Components/Footnote/Footnote.swift | 2 +- VDS/Components/Footnote/FootnoteGroup.swift | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/Footnote.swift index 4d352e7b..0de37b45 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/Footnote.swift @@ -132,7 +132,7 @@ open class Footnote: View { private lazy var itemStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal - $0.alignment = .top + $0.alignment = .leading $0.distribution = .fill $0.spacing = VDSLayout.space1X $0.backgroundColor = .clear diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift index 0f229ac8..9660f440 100644 --- a/VDS/Components/Footnote/FootnoteGroup.swift +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -75,7 +75,6 @@ open class FootnoteGroup: View { private lazy var stackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .vertical - $0.alignment = .top $0.distribution = .fill $0.spacing = VDSLayout.space3X $0.backgroundColor = .clear From 2854aea8c22213c1a8d867018718aa803928c6e6 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Wed, 18 Sep 2024 12:19:35 +0530 Subject: [PATCH 08/13] refactored naming Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 8 ++++---- VDS/Components/Footnote/FootnoteGroup.swift | 8 ++++---- .../{Footnote.swift => FootnoteItem.swift} | 14 ++++++-------- 3 files changed, 14 insertions(+), 16 deletions(-) rename VDS/Components/Footnote/{Footnote.swift => FootnoteItem.swift} (94%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 67eb6f60..7090dcfd 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -21,7 +21,7 @@ 1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; }; 186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; - 18926F5B2C7616A500C55BF6 /* Footnote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18926F5A2C7616A500C55BF6 /* Footnote.swift */; }; + 18926F5B2C7616A500C55BF6 /* FootnoteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */; }; 18926F5D2C7616C600C55BF6 /* FootnoteChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */; }; 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; @@ -233,7 +233,7 @@ 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = ""; }; 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; - 18926F5A2C7616A500C55BF6 /* Footnote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Footnote.swift; sourceTree = ""; }; + 18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FootnoteItem.swift; sourceTree = ""; }; 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = FootnoteChangeLog.txt; sourceTree = ""; }; 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; @@ -505,7 +505,7 @@ 18926F592C76168300C55BF6 /* Footnote */ = { isa = PBXGroup; children = ( - 18926F5A2C7616A500C55BF6 /* Footnote.swift */, + 18926F5A2C7616A500C55BF6 /* FootnoteItem.swift */, 183B16F62C80B32200BA6A10 /* FootnoteGroup.swift */, 18926F5C2C7616C600C55BF6 /* FootnoteChangeLog.txt */, ); @@ -1328,7 +1328,7 @@ 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */, EAF2F4762C231EAA007BFEDC /* AccessibilityActionElement.swift in Sources */, EAC58BFD2BE935C300BA39FA /* TitleLockupTextColor.swift in Sources */, - 18926F5B2C7616A500C55BF6 /* Footnote.swift in Sources */, + 18926F5B2C7616A500C55BF6 /* FootnoteItem.swift in Sources */, EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAF193422C134F3400C68D18 /* Table.swift in Sources */, diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift index 9660f440..693639ee 100644 --- a/VDS/Components/Footnote/FootnoteGroup.swift +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -42,7 +42,7 @@ open class FootnoteGroup: View { // MARK: - Public Properties //-------------------------------------------------- /// Array of ``Footnote`` for the Footnote items. - open var footnoteItems: [Footnote] = [] { didSet { setNeedsUpdate() } } + open var footnoteItems: [FootnoteItem] = [] { didSet { setNeedsUpdate() } } /// Any percentage or pixel value and cannot exceed container size. /// If there is a width that is larger than container size, the footnote will resize to container's width. @@ -132,7 +132,7 @@ open class FootnoteGroup: View { var symbolMaxWidth = 0.0 if footnoteItems.count > 0 { for index in 0...footnoteItems.count - 1 { - let footnote: Footnote = footnoteItems[index] + let footnote: FootnoteItem = footnoteItems[index] let separatorWidth = Label().with { $0.text = footnote.symbolType; $0.sizeToFit() }.intrinsicContentSize.width symbolMaxWidth = separatorWidth > symbolMaxWidth ? separatorWidth : symbolMaxWidth } @@ -142,8 +142,8 @@ open class FootnoteGroup: View { // add symbol label, text label to stack. if footnoteItems.count > 0 { for index in 0...footnoteItems.count - 1 { - let footnote: Footnote = footnoteItems[index] - footnote.symbolWiderWidth = symbolMaxWidth + let footnote: FootnoteItem = footnoteItems[index] + footnote.symbolWidth = symbolMaxWidth footnote.surface = surface stackView.addArrangedSubview(footnote) } diff --git a/VDS/Components/Footnote/Footnote.swift b/VDS/Components/Footnote/FootnoteItem.swift similarity index 94% rename from VDS/Components/Footnote/Footnote.swift rename to VDS/Components/Footnote/FootnoteItem.swift index 0de37b45..ebd6e6ab 100644 --- a/VDS/Components/Footnote/Footnote.swift +++ b/VDS/Components/Footnote/FootnoteItem.swift @@ -12,8 +12,8 @@ import VDSCoreTokens /// A footnote is text that provides supporting details, legal copy and links to related content. /// It exists at the bottom or "foot" of a page or section. @objcMembers -@objc(VDSFootnote) -open class Footnote: View { +@objc(VDSFootnoteItem) +open class FootnoteItem: View { //-------------------------------------------------- // MARK: - Initializers @@ -122,7 +122,7 @@ open class Footnote: View { } /// To set the widest symbol width from the symbol container in the group. - open var symbolWiderWidth: CGFloat = 0 { didSet { setNeedsUpdate() } } + internal var symbolWidth: CGFloat? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties @@ -210,7 +210,6 @@ open class Footnote: View { super.updateView() // Update symbolLabel - symbolWidthConstraint?.isActive = false symbolLabel.text = symbolType symbolLabel.isHidden = hideSymbol symbolLabel.textColor = kind.colorConfiguration.getColor(self) @@ -218,13 +217,12 @@ open class Footnote: View { symbolLabel.surface = surface //Set width to the symbol label - if symbolWiderWidth > 0 { + if let symbolWidth, symbolWidth > 0 { // Set the widest symbol width from the symbol container in the group. - symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolWiderWidth) + symbolWidthConstraint?.constant = symbolWidth } else { - symbolWidthConstraint = symbolLabel.widthAnchor.constraint(equalToConstant: symbolLabel.intrinsicContentSize.width) + symbolWidthConstraint?.constant = symbolLabel.intrinsicContentSize.width } - symbolWidthConstraint?.isActive = true // Update textLabel textLabel.text = text From 9f6c115f50ef75a359e932762c8de2f279bdf543 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 18 Sep 2024 15:00:27 -0500 Subject: [PATCH 09/13] made internal since only group uses this Signed-off-by: Matt Bruce --- VDS/Components/Footnote/FootnoteItem.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/VDS/Components/Footnote/FootnoteItem.swift b/VDS/Components/Footnote/FootnoteItem.swift index ebd6e6ab..98233b3a 100644 --- a/VDS/Components/Footnote/FootnoteItem.swift +++ b/VDS/Components/Footnote/FootnoteItem.swift @@ -120,15 +120,15 @@ open class FootnoteItem: View { setNeedsUpdate() } } - - /// To set the widest symbol width from the symbol container in the group. - internal var symbolWidth: CGFloat? { didSet { setNeedsUpdate() } } - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var _width: Width? = nil - + + /// To set the widest symbol width from the symbol container in the group. + internal var symbolWidth: CGFloat? { didSet { setNeedsUpdate() } } + private lazy var itemStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal From 8ce9108d4595cc20ddb4362e132031a551ad89cb Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 18 Sep 2024 15:14:39 -0500 Subject: [PATCH 10/13] refactored the adding of footnotes similar to the Tabs Signed-off-by: Matt Bruce --- VDS/Components/Footnote/FootnoteGroup.swift | 34 +++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift index 693639ee..cb129f04 100644 --- a/VDS/Components/Footnote/FootnoteGroup.swift +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -42,7 +42,7 @@ open class FootnoteGroup: View { // MARK: - Public Properties //-------------------------------------------------- /// Array of ``Footnote`` for the Footnote items. - open var footnoteItems: [FootnoteItem] = [] { didSet { setNeedsUpdate() } } + open var footnoteItems: [FootnoteItem] = [] { didSet { updateFootnoteItems() } } /// Any percentage or pixel value and cannot exceed container size. /// If there is a width that is larger than container size, the footnote will resize to container's width. @@ -127,26 +127,28 @@ open class FootnoteGroup: View { open override func updateView() { super.updateView() updateContainerWidth() - + } + + internal func updateFootnoteItems() { // symbol containers are as wide as the widest symbol container in the group. var symbolMaxWidth = 0.0 - if footnoteItems.count > 0 { - for index in 0...footnoteItems.count - 1 { - let footnote: FootnoteItem = footnoteItems[index] - let separatorWidth = Label().with { $0.text = footnote.symbolType; $0.sizeToFit() }.intrinsicContentSize.width - symbolMaxWidth = separatorWidth > symbolMaxWidth ? separatorWidth : symbolMaxWidth - } + + footnoteItems.forEach { footnote in + let separatorWidth = Label().with { + $0.text = footnote.symbolType + $0.textStyle = footnote.symbolLabel.textStyle + $0.sizeToFit() + }.intrinsicContentSize.width + symbolMaxWidth = max(separatorWidth, symbolMaxWidth) } - stackView.subviews.forEach{$0.removeFromSuperview()} + stackView.removeArrangedSubviews() + // add symbol label, text label to stack. - if footnoteItems.count > 0 { - for index in 0...footnoteItems.count - 1 { - let footnote: FootnoteItem = footnoteItems[index] - footnote.symbolWidth = symbolMaxWidth - footnote.surface = surface - stackView.addArrangedSubview(footnote) - } + footnoteItems.forEach { footnote in + footnote.symbolWidth = symbolMaxWidth + footnote.surface = surface + stackView.addArrangedSubview(footnote) } } From 58b83fc37f4682d441a3a37ebb9febc0eb77c580 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 19 Sep 2024 14:33:31 -0500 Subject: [PATCH 11/13] rename class for docs Signed-off-by: Matt Bruce --- VDS/VDS.docc/VDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index d1afd2b1..97036331 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -32,7 +32,7 @@ Using the system allows designers and developers to collaborate more easily and - ``CheckboxItem`` - ``CheckboxGroup`` - ``DropdownSelect`` -- ``Footnote`` +- ``FootnoteItem`` - ``FootnoteGroup`` - ``Icon`` - ``InputStepper`` From 8028c8a7854c352b895111315ecff4f4b5aaa539 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 19 Sep 2024 14:34:24 -0500 Subject: [PATCH 12/13] removed constraints and for this class to be setup correctly in its parent rather than doing it in the view. similar to how UIButton works. --- VDS/Components/Footnote/FootnoteGroup.swift | 39 +++++---------------- VDS/Components/Footnote/FootnoteItem.swift | 23 ++++-------- 2 files changed, 15 insertions(+), 47 deletions(-) diff --git a/VDS/Components/Footnote/FootnoteGroup.swift b/VDS/Components/Footnote/FootnoteGroup.swift index cb129f04..5d325d8b 100644 --- a/VDS/Components/Footnote/FootnoteGroup.swift +++ b/VDS/Components/Footnote/FootnoteGroup.swift @@ -63,7 +63,7 @@ open class FootnoteGroup: View { } else { _width = nil } - setNeedsUpdate() + updateContainerWidth() } } @@ -83,7 +83,7 @@ open class FootnoteGroup: View { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- - internal var maxWidth: CGFloat { frame.size.width } + internal var maxWidth: CGFloat { horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width) } internal var minWidth: CGFloat { containerSize.width } internal var containerSize: CGSize { CGSize(width: 55, height: 44) } @@ -91,8 +91,6 @@ open class FootnoteGroup: View { // MARK: - Constraints //-------------------------------------------------- internal var widthConstraint: NSLayoutConstraint? - internal var trailingEqualsConstraint: NSLayoutConstraint? - internal var trailingLessThanEqualsConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Overrides @@ -104,12 +102,8 @@ open class FootnoteGroup: View { // add footnote item stackview. addSubview(stackView) - stackView.pinTop().pinBottom().pinLeading() - trailingEqualsConstraint = stackView.pinTrailing(anchor: trailingAnchor) - - // width constraints - trailingLessThanEqualsConstraint = stackView.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate() - widthConstraint = stackView.widthAnchor.constraint(equalToConstant: 0).deactivate() + stackView.pinToSuperView() + widthConstraint = widthAnchor.constraint(equalToConstant: 0).deactivate() } open override func setDefaults() { @@ -117,18 +111,7 @@ open class FootnoteGroup: View { width = nil footnoteItems = [] } - - /// 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() - updateContainerWidth() - } - + internal func updateFootnoteItems() { // symbol containers are as wide as the widest symbol container in the group. var symbolMaxWidth = 0.0 @@ -151,10 +134,11 @@ open class FootnoteGroup: View { stackView.addArrangedSubview(footnote) } } - + /// Update container width after updating content. internal func updateContainerWidth() { var newWidth = 0.0 + switch width { case .percentage(let percentage): newWidth = max(maxWidth * ((percentage) / 100), minWidth) @@ -162,20 +146,15 @@ open class FootnoteGroup: View { case .value(let value): newWidth = value > maxWidth ? maxWidth : value - case nil: - newWidth = maxWidth + case nil: break + } widthConstraint?.deactivate() - trailingLessThanEqualsConstraint?.deactivate() - trailingEqualsConstraint?.deactivate() if newWidth > minWidth && newWidth < maxWidth { widthConstraint?.constant = newWidth widthConstraint?.activate() - trailingLessThanEqualsConstraint?.activate() - } else { - trailingEqualsConstraint?.activate() } } } diff --git a/VDS/Components/Footnote/FootnoteItem.swift b/VDS/Components/Footnote/FootnoteItem.swift index 98233b3a..489c05be 100644 --- a/VDS/Components/Footnote/FootnoteItem.swift +++ b/VDS/Components/Footnote/FootnoteItem.swift @@ -117,7 +117,7 @@ open class FootnoteItem: View { } else { _width = nil } - setNeedsUpdate() + updateContainerWidth() } } @@ -152,7 +152,7 @@ open class FootnoteItem: View { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- - internal var maxWidth: CGFloat { frame.size.width } + internal var maxWidth: CGFloat { horizontalPinnedWidth() ?? (superview?.frame.size.width ?? frame.size.width) } internal var minWidth: CGFloat { containerSize.width } internal var containerSize: CGSize { CGSize(width: 45, height: 44) } @@ -161,8 +161,6 @@ open class FootnoteItem: View { //-------------------------------------------------- internal var symbolWidthConstraint: NSLayoutConstraint? internal var itemWidthConstraint: NSLayoutConstraint? - internal var trailingEqualsConstraint: NSLayoutConstraint? - internal var trailingLessThanEqualsConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Overrides @@ -174,12 +172,10 @@ open class FootnoteItem: View { // add footnote item stackview. addSubview(itemStackView) - itemStackView.pinTop().pinBottom().pinLeading() - trailingEqualsConstraint = itemStackView.pinTrailing(anchor: trailingAnchor) + itemStackView.pinToSuperView() // width constraints - itemWidthConstraint = itemStackView.widthAnchor.constraint(equalToConstant: 0).deactivate() - trailingLessThanEqualsConstraint = itemStackView.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate() + itemWidthConstraint = widthAnchor.constraint(equalToConstant: 0).deactivate() // add symbol label, text label to stack. itemStackView.addArrangedSubview(symbolLabel) @@ -236,8 +232,6 @@ open class FootnoteItem: View { attributes.append(TooltipLabelAttribute(surface: surface, model: tooltipModel, presenter: self)) textLabel.attributes = attributes } - - updateContainerWidth() } /// Update container width after updating content. @@ -251,18 +245,13 @@ open class FootnoteItem: View { newWidth = value > maxWidth ? maxWidth : value case nil: - newWidth = maxWidth - } + break + } itemWidthConstraint?.deactivate() - trailingLessThanEqualsConstraint?.deactivate() - trailingEqualsConstraint?.deactivate() if newWidth > minWidth && newWidth < maxWidth { itemWidthConstraint?.constant = newWidth itemWidthConstraint?.activate() - trailingLessThanEqualsConstraint?.activate() - } else { - trailingEqualsConstraint?.activate() } } } From e1f88e600b7933c5e42aec78ceaa8af5a3515115 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 19 Sep 2024 14:34:39 -0500 Subject: [PATCH 13/13] fixed issue with SelectorItemBase Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorItemBase.swift | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 321df2a8..af415c5c 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -43,13 +43,14 @@ open class SelectorItemBase: Control, Errorable, Changea private var mainStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .top + $0.alignment = .fill $0.axis = .vertical } private var selectorStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .top + $0.alignment = .fill + $0.axis = .horizontal } @@ -171,10 +172,16 @@ open class SelectorItemBase: Control, Errorable, Changea isAccessibilityElement = false addSubview(mainStackView) - mainStackView.isUserInteractionEnabled = false + //wrap the selectorView in a view that won't stretch it + //do this by not pinning the bottom + let selectorViewWrapper = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } + selectorViewWrapper.addSubview(selectorView) + selectorView.pinTop().pinLeading().pinTrailing().pinBottomLessThanOrEqualTo() + + mainStackView.isUserInteractionEnabled = false mainStackView.addArrangedSubview(selectorStackView) mainStackView.addArrangedSubview(errorLabel) - selectorStackView.addArrangedSubview(selectorView) + selectorStackView.addArrangedSubview(selectorViewWrapper) selectorStackView.addArrangedSubview(selectorLabelStackView) selectorLabelStackView.addArrangedSubview(label) selectorLabelStackView.addArrangedSubview(childLabel)