From 6290a4300404c9d7726dde2af2d4d4b8445931d3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 10:53:13 -0500 Subject: [PATCH 01/11] removed intrinsic size Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonBase.swift | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index cc096d41..e8a379d9 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -141,17 +141,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { shouldUpdateView = true setNeedsUpdate() } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - override open var intrinsicContentSize: CGSize { - let intrinsicContentSize = super.intrinsicContentSize - let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right - let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom - return CGSize(width: adjustedWidth, height: adjustedHeight) - } - + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- From 2e0d0be8b68786b9be98add64b9576be1771a139 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 10:53:42 -0500 Subject: [PATCH 02/11] left aligned content for scenarios to where the container is stretched. Signed-off-by: Matt Bruce --- VDS/Components/Buttons/TextLink/TextLink.swift | 4 ++++ VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index dcb4a46d..1b1f79e8 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -87,6 +87,10 @@ open class TextLink: ButtonBase { isAccessibilityElement = true accessibilityTraits = .link + //left align titleLabel in case this is pinned leading/trailing + //default is always set to center + contentHorizontalAlignment = .left + if let titleLabel { addSubview(line) line.pinLeading(titleLabel.leadingAnchor) diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index aaa9f3cb..eb3776ea 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -79,6 +79,11 @@ open class TextLinkCaret: ButtonBase { /// 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() + + //left align titleLabel in case this is pinned leading/trailing + //default is always set to center + contentHorizontalAlignment = .left + accessibilityTraits = .link titleLabel?.numberOfLines = 0 titleLabel?.lineBreakMode = .byWordWrapping From 51562aa58900977d168ece15e20d5c9a3627cec6 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 11:13:23 -0500 Subject: [PATCH 03/11] fixed issues for intrinsicSize Signed-off-by: Matt Bruce --- VDS/Components/Buttons/TextLink/TextLink.swift | 8 +++++++- .../Buttons/TextLinkCaret/TextLinkCaret.swift | 11 ++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 1b1f79e8..51221b34 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -75,7 +75,13 @@ open class TextLink: 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 } //-------------------------------------------------- diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index eb3776ea..f02d2b10 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -103,9 +103,14 @@ open class TextLinkCaret: ButtonBase { } /// The natural size for the receiving view, considering only properties of the view itself. - override open var intrinsicContentSize: CGSize { - //get the labels size, if not the button - return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize + open override var intrinsicContentSize: CGSize { + 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 } } From d76da5d216fc547fc5a6274f5c0389640c6844fd Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 10:53:13 -0500 Subject: [PATCH 04/11] removed intrinsic size Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonBase.swift | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index cc096d41..e8a379d9 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -141,17 +141,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { shouldUpdateView = true setNeedsUpdate() } - - //-------------------------------------------------- - // MARK: - Overrides - //-------------------------------------------------- - override open var intrinsicContentSize: CGSize { - let intrinsicContentSize = super.intrinsicContentSize - let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right - let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom - return CGSize(width: adjustedWidth, height: adjustedHeight) - } - + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- From 3c8176062c300804c6d7f8228241f67a0803e9be Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 10:53:42 -0500 Subject: [PATCH 05/11] left aligned content for scenarios to where the container is stretched. Signed-off-by: Matt Bruce --- VDS/Components/Buttons/TextLink/TextLink.swift | 4 ++++ VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index dcb4a46d..1b1f79e8 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -87,6 +87,10 @@ open class TextLink: ButtonBase { isAccessibilityElement = true accessibilityTraits = .link + //left align titleLabel in case this is pinned leading/trailing + //default is always set to center + contentHorizontalAlignment = .left + if let titleLabel { addSubview(line) line.pinLeading(titleLabel.leadingAnchor) diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index aaa9f3cb..eb3776ea 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -79,6 +79,11 @@ open class TextLinkCaret: ButtonBase { /// 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() + + //left align titleLabel in case this is pinned leading/trailing + //default is always set to center + contentHorizontalAlignment = .left + accessibilityTraits = .link titleLabel?.numberOfLines = 0 titleLabel?.lineBreakMode = .byWordWrapping From 7d892b3190217fce828cf5dd9b33bd9d0e116c59 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 11:13:23 -0500 Subject: [PATCH 06/11] fixed issues for intrinsicSize Signed-off-by: Matt Bruce --- VDS/Components/Buttons/TextLink/TextLink.swift | 8 +++++++- .../Buttons/TextLinkCaret/TextLinkCaret.swift | 11 ++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 1b1f79e8..51221b34 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -75,7 +75,13 @@ open class TextLink: 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 } //-------------------------------------------------- diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index eb3776ea..f02d2b10 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -103,9 +103,14 @@ open class TextLinkCaret: ButtonBase { } /// The natural size for the receiving view, considering only properties of the view itself. - override open var intrinsicContentSize: CGSize { - //get the labels size, if not the button - return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize + open override var intrinsicContentSize: CGSize { + 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 } } From 597753e3c01cd9b836611b66cdca5dbbf0dfc15d Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 16:30:29 -0500 Subject: [PATCH 07/11] added invalidateCOntentSize after label updates Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonBase.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index e8a379d9..46f72c55 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -146,7 +146,8 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { // MARK: - Private Methods //-------------------------------------------------- private func updateLabel() { - + defer { invalidateIntrinsicContentSize() } + //clear the arrays holding actions accessibilityCustomActions = [] if let text, !text.isEmpty { From 0258fba13b49290767d3a9c1071ca9a3fd3ed0dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 18 Mar 2024 16:51:02 -0500 Subject: [PATCH 08/11] fixed bug in multiline label within UIbutton Signed-off-by: Matt Bruce --- .../Buttons/TextLinkCaret/TextLinkCaret.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index f02d2b10..df276354 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -106,12 +106,20 @@ open class TextLinkCaret: ButtonBase { open override var intrinsicContentSize: CGSize { 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)) + let labelSize = titleLabel.sizeThatFits(CGSize(width: self.frame.width - (contentEdgeInsets.left + contentEdgeInsets.right), 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 } + + open override func layoutSubviews() { + super.layoutSubviews() + // This ensures the titleLabel is correctly positioned within the button + titleLabel?.preferredMaxLayoutWidth = self.frame.width - (contentEdgeInsets.left + contentEdgeInsets.right) + super.layoutSubviews() // Calling super again to ensure layout is updated with preferredMaxLayoutWidth + } + } extension TextLinkCaret { From 9203b6cab59a72c17b8324b373c105b0b4da4948 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 20 Mar 2024 15:24:35 -0500 Subject: [PATCH 09/11] added/updated isValid(range: Signed-off-by: Matt Bruce --- .../Label/Attributes/LabelAttributeModel.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Label/Attributes/LabelAttributeModel.swift b/VDS/Components/Label/Attributes/LabelAttributeModel.swift index ac43472f..01dfec08 100644 --- a/VDS/Components/Label/Attributes/LabelAttributeModel.swift +++ b/VDS/Components/Label/Attributes/LabelAttributeModel.swift @@ -31,11 +31,21 @@ extension LabelAttributeModel { } public func isValidRange(on attributedString: NSMutableAttributedString) -> Bool { - range.location + range.length <= attributedString.string.count + attributedString.isValid(range: range) + } +} + +public extension String { + func isValid(range: NSRange) -> Bool { + range.location >= 0 && range.length > 0 && range.location + range.length <= count } } public extension NSAttributedString { + func isValid(range: NSRange) -> Bool { + range.location >= 0 && range.length > 0 && range.location + range.length <= length + } + func createAttributeModels() -> [(any LabelAttributeModel)] { var attributes: [any VDS.LabelAttributeModel] = [] enumerateAttributes(in: NSMakeRange(0, length)) { attributeMap, range, stop in @@ -61,6 +71,7 @@ public extension NSAttributedString { extension NSMutableAttributedString { public func apply(attribute: any LabelAttributeModel) { + guard isValid(range: attribute.range) else { return } attribute.setAttribute(on: self) } From 1d9667c1736cd404c85e7af7f09db393a39cf729 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 20 Mar 2024 15:24:59 -0500 Subject: [PATCH 10/11] added validators for invalid range Signed-off-by: Matt Bruce --- VDS/Components/Label/Attributes/ActionLabelAttribute.swift | 2 ++ .../Label/Attributes/AttachmentLabelAttributeModel.swift | 2 ++ VDS/Components/Label/Attributes/TooltipLabelAttribute.swift | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Label/Attributes/ActionLabelAttribute.swift b/VDS/Components/Label/Attributes/ActionLabelAttribute.swift index acd28f91..6d7a1034 100644 --- a/VDS/Components/Label/Attributes/ActionLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/ActionLabelAttribute.swift @@ -56,6 +56,8 @@ public struct ActionLabelAttribute: ActionLabelAttributeModel { } public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } + if(shouldUnderline){ UnderlineLabelAttribute(location: location, length: length).setAttribute(on: attributedString) } diff --git a/VDS/Components/Label/Attributes/AttachmentLabelAttributeModel.swift b/VDS/Components/Label/Attributes/AttachmentLabelAttributeModel.swift index 5de6f4b2..c4f9bd79 100644 --- a/VDS/Components/Label/Attributes/AttachmentLabelAttributeModel.swift +++ b/VDS/Components/Label/Attributes/AttachmentLabelAttributeModel.swift @@ -14,6 +14,8 @@ public protocol AttachmentLabelAttributeModel: LabelAttributeModel { extension AttachmentLabelAttributeModel { public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } + do { let mutableString = NSMutableAttributedString() let attachment = try getAttachment() diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 914a8783..bd02cf87 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -24,7 +24,9 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable public var presenter: UIView? public func setAttribute(on attributedString: NSMutableAttributedString) { - //update the location + guard isValidRange(on: attributedString) else { return } + + //update the location location = attributedString.string.count - 1 //set the default color off surface for text From 0fc70e9f7542cc5baa68b3397f66eb0fe60e8e76 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 20 Mar 2024 15:29:24 -0500 Subject: [PATCH 11/11] ensure range is valid. Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 955d9604..c0edef0b 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -344,7 +344,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { for attribute in attributes { //see if the attribute is Actionable - if let actionable = attribute as? any ActionLabelAttributeModel{ + if let actionable = attribute as? any ActionLabelAttributeModel, mutableAttributedString.isValid(range: actionable.range) { //create a accessibleAction let customAccessibilityAction = customAccessibilityAction(text: mutableAttributedString.string, range: actionable.range, accessibleText: actionable.accessibleText) @@ -379,7 +379,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { guard let text = text, let attributedText else { return nil } - let actionText = accessibleText ?? NSString(string:text).substring(with: range) + let actionText = accessibleText ?? (text.isValid(range: range) ? NSString(string:text).substring(with: range) : text) // Calculate the frame of the substring let layoutManager = NSLayoutManager()