From 6e97efa4fffce09367f29184b1beec2f5b2ecb54 Mon Sep 17 00:00:00 2001 From: Alex Odawa Date: Tue, 11 Jun 2024 18:38:02 +0200 Subject: [PATCH 01/14] AttributedLabel Link Accessibility (#459) Updating attributed label's links to more closely mirror the SwiftUI accessibility experience https://github.com/square/Blueprint/assets/219578/7255cbc0-2c6a-41a5-a0bc-9cd5ec5774c4 This is our current implementation, which doesn't announce links properly. https://github.com/square/Blueprint/assets/219578/11c3e109-c632-4542-9e5b-11eddf618eba Here is the new version, announcing links as they are read. https://github.com/square/Blueprint/assets/219578/38aad435-825b-42f4-b65f-a70b5757691a --- .../Keys/AccessibilityLinkKey.swift | 17 +++++++ .../Sources/AttributedLabel.swift | 44 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 BlueprintUI/Sources/Environment/Keys/AccessibilityLinkKey.swift diff --git a/BlueprintUI/Sources/Environment/Keys/AccessibilityLinkKey.swift b/BlueprintUI/Sources/Environment/Keys/AccessibilityLinkKey.swift new file mode 100644 index 000000000..3f0a5cbe9 --- /dev/null +++ b/BlueprintUI/Sources/Environment/Keys/AccessibilityLinkKey.swift @@ -0,0 +1,17 @@ +import UIKit + +extension Environment { + private enum LinkAccesibilityLabelKey: EnvironmentKey { + static var defaultValue: String? { + UIImage(systemName: "link")?.accessibilityLabel + } + } + + /// The localised accessibility label elements should use when handling links. + /// + /// Defaults to `UIImage(systemName: "link")?.accessibilityLabel`. + public var linkAccessibilityLabel: String? { + get { self[LinkAccesibilityLabelKey.self] } + set { self[LinkAccesibilityLabelKey.self] = newValue } + } +} diff --git a/BlueprintUICommonControls/Sources/AttributedLabel.swift b/BlueprintUICommonControls/Sources/AttributedLabel.swift index 1b124bc90..be1e0473a 100644 --- a/BlueprintUICommonControls/Sources/AttributedLabel.swift +++ b/BlueprintUICommonControls/Sources/AttributedLabel.swift @@ -265,6 +265,11 @@ extension AttributedLabel { if previousAttributedText != attributedText { links = attributedLinks(in: model.attributedText) + detectedDataLinks(in: model.attributedText) accessibilityLinks = accessibilityLinks(for: links, in: model.attributedText) + accessibilityLabel = accessibilityLabel( + with: links, + in: model.attributedText.string, + linkAccessibilityLabel: environment.linkAccessibilityLabel + ) } if let shadow = model.shadow { @@ -537,6 +542,45 @@ extension AttributedLabel { link: link ) } + + + } + + private func accessibilityLabel(with links: [Link], in string: String, linkAccessibilityLabel: String?) -> String { + // When reading an attributed string that contains the `.link` attribute VoiceOver will announce "link" when it encounters the applied range. This is important because it informs the user about the context and position of the linked text within the greater string. This can be partocularly important when a string contains multiple links with the same linked text but different link destinations. + + // UILabel is extremely insistant about how the `.link` attribute should be styled going so far as to apply its own preferences above any other provided attributes. In order to allow custom link styling we replace any instances of the `.link` attribute with a `labelLink.` attribute (see `NSAttributedString.normalizingForView(with:)`. This allows us to track the location of links while still providing our own custom styling. Unfortunately this means that voiceover doesnt recognize our links as links and consequently they are not announced to the user. + + // Ideally we'd be able to enumerate our links, insert the `.link` attribute back and then set the resulting string as the `accessibilityAttributedString` but unfortunately that doesnt seem to work. Apple's [docs](https://developer.apple.com/documentation/objectivec/nsobject/2865944-accessibilityattributedlabel) indicate that this property is intended "for the inclusion of language attributes in the string to control pronunciation or accents" and doesnt seem to notice any included `.link` attributes. + + // Insert the word "link" after each link in the label. This mirrors the VoiceOver behavior when encountering a `.link` attribute. + + guard let localizedLinkString = linkAccessibilityLabel, + !links.isEmpty else { return string } + var label = string + // Wrap the word in [brackets] to indicate that it is a tag distinct from the content string. This is transparent to voiceover but should be helpful when the accessibility label is printed e.g. in the accessibility inspector. + + // The use of square brackets is arbitrary but was chosen because: + // • Voiceover doesn't read the [] characters, but does realize the contained word is distinct from the preceding word. + // • Square brackets aren't often used in prose, unlike parenthesis. They're unlikely to be confused with the actual content. + // • They look like markdown. + + let insertionString = "[\(localizedLinkString)] " + // Insert from the end of the string to keep indices stable. + let reversed = links.sorted { $0.range.location > $1.range.location } + for link in reversed { + let insertionPoint = label.index(label.startIndex, offsetBy: link.range.location + link.range.length) + let insertionEnd = label.index( + insertionPoint, + offsetBy: insertionString.count, + limitedBy: label.endIndex + ) + if insertionEnd != nil && label[insertionPoint...(insertionEnd ?? insertionPoint)] == insertionString { + continue + } + label.insert(contentsOf: insertionString, at: insertionPoint) + } + return label } func applyLinkColors(activeLinks: [Link] = []) { From 62c137648c53bb38119cdad59501aa4e302356dc Mon Sep 17 00:00:00 2001 From: Alex Odawa Date: Thu, 13 Jun 2024 19:54:46 +0200 Subject: [PATCH 02/14] bumping version to 4.1.0 (#499) Bump to 4.1.0 to include new link accessibility fixes https://github.com/square/Blueprint/pull/459/ --- CHANGELOG.md | 8 +++++++- SampleApp/Podfile.lock | 12 ++++++------ version.rb | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0deac32a0..425a1c4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Past Releases +## [4.1.0] - 2024-06-04 + +### Fixed +- Fixed a bug where `AttributedLabel`'s accessibility utterance was not properly announcing links. + ## [4.0.1] - 2024-06-04 ### Fixed @@ -1080,7 +1085,8 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.0.1...HEAD +[main]: https://github.com/square/Blueprint/compare/4.1.0...HEAD +[4.1.0]: https://github.com/square/Blueprint/compare/4.0.1...4.1.0 [4.0.1]: https://github.com/square/Blueprint/compare/4.0.0...4.0.1 [4.0.0]: https://github.com/square/Blueprint/compare/3.1.0...4.0.0 [3.1.0]: https://github.com/square/Blueprint/compare/3.0.0...3.1.0 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index 2c0e8474d..5bb84eb8b 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.0.1) - - BlueprintUI/Tests (4.0.1) - - BlueprintUICommonControls (4.0.1): - - BlueprintUI (= 4.0.1) + - BlueprintUI (4.1.0) + - BlueprintUI/Tests (4.1.0) + - BlueprintUICommonControls (4.1.0): + - BlueprintUI (= 4.1.0) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: 9628bfc92acbe53cb9bed04978a552c343a09726 - BlueprintUICommonControls: 1b0c018299c541dd57459e76512a025bdc3d4ee7 + BlueprintUI: e3977b3657a5ce03b61b55a8e5cfdcae32c772b4 + BlueprintUICommonControls: 8c3c5a718be323baab2c01093978f2735553e035 PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index cf4547e4b..2e8504e4c 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.0.1' +BLUEPRINT_VERSION ||= '4.1.0' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version')) From 15532856e641b4fbc8f36f2fe1dd7e54528e88f5 Mon Sep 17 00:00:00 2001 From: Alex Odawa Date: Fri, 14 Jun 2024 03:48:36 +0200 Subject: [PATCH 03/14] Fix string index out of bounds crash. (#501) Well, this is always embarrassing. `string.startIndex...string.endIndex` is out of bounds, which seems counter to my understanding of either ranges or string indices but I'm not sure which . Regardless, we need a half open range here. --- .../Sources/AttributedLabel.swift | 23 +++++- .../Tests/Sources/AttributedLabelTests.swift | 81 +++++++++++++++++++ CHANGELOG.md | 7 +- SampleApp/Podfile.lock | 12 +-- version.rb | 2 +- 5 files changed, 112 insertions(+), 13 deletions(-) diff --git a/BlueprintUICommonControls/Sources/AttributedLabel.swift b/BlueprintUICommonControls/Sources/AttributedLabel.swift index be1e0473a..8349a9098 100644 --- a/BlueprintUICommonControls/Sources/AttributedLabel.swift +++ b/BlueprintUICommonControls/Sources/AttributedLabel.swift @@ -546,7 +546,7 @@ extension AttributedLabel { } - private func accessibilityLabel(with links: [Link], in string: String, linkAccessibilityLabel: String?) -> String { + internal func accessibilityLabel(with links: [Link], in string: String, linkAccessibilityLabel: String?) -> String { // When reading an attributed string that contains the `.link` attribute VoiceOver will announce "link" when it encounters the applied range. This is important because it informs the user about the context and position of the linked text within the greater string. This can be partocularly important when a string contains multiple links with the same linked text but different link destinations. // UILabel is extremely insistant about how the `.link` attribute should be styled going so far as to apply its own preferences above any other provided attributes. In order to allow custom link styling we replace any instances of the `.link` attribute with a `labelLink.` attribute (see `NSAttributedString.normalizingForView(with:)`. This allows us to track the location of links while still providing our own custom styling. Unfortunately this means that voiceover doesnt recognize our links as links and consequently they are not announced to the user. @@ -565,17 +565,32 @@ extension AttributedLabel { // • Square brackets aren't often used in prose, unlike parenthesis. They're unlikely to be confused with the actual content. // • They look like markdown. - let insertionString = "[\(localizedLinkString)] " + let insertionString = "[\(localizedLinkString)]" // Insert from the end of the string to keep indices stable. let reversed = links.sorted { $0.range.location > $1.range.location } for link in reversed { - let insertionPoint = label.index(label.startIndex, offsetBy: link.range.location + link.range.length) + // Extract substring from NSString to align with NSRange provided by the link. + let nsstring = string as NSString + guard link.range.location >= 0, + link.range.length >= 0, + link.range.location + link.range.length <= nsstring.length + else { + continue + } + let substring = nsstring.substring(with: link.range) + + // Generate swift range from substring + guard let swiftRange = string.range(of: substring) else { + continue + } + let insertionPoint = swiftRange.upperBound + let insertionEnd = label.index( insertionPoint, offsetBy: insertionString.count, limitedBy: label.endIndex ) - if insertionEnd != nil && label[insertionPoint...(insertionEnd ?? insertionPoint)] == insertionString { + if insertionEnd != nil && label[insertionPoint..<(insertionEnd ?? insertionPoint)] == insertionString { continue } label.insert(contentsOf: insertionString, at: insertionPoint) diff --git a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift index 6235f080c..ed58e802a 100644 --- a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift +++ b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift @@ -357,6 +357,87 @@ class AttributedLabelTests: XCTestCase { compareSnapshot(of: element) } + func test_linkAccessibility() { + let labelview = AttributedLabel.LabelView() + + do { + // Test that link insertion happy path works + let string = NSString("Foo Bar Baz") + let url = URL(string: "https://block.xyz")! + for (word, result) in [ + ("Foo", "Foo[Link] Bar Baz"), + ("Bar", "Foo Bar[Link] Baz"), + ("Baz", "Foo Bar Baz[Link]"), + ] { + let range = string.range(of: word) + let link = AttributedLabel.Link(url: url, range: range) + let accessibilityLabel = labelview.accessibilityLabel( + with: [link], + in: string as String, + linkAccessibilityLabel: "Link" + ) + XCTAssertEqual(accessibilityLabel, result) + } + } + + do { + // Test every position + let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + let string = numbers.map { String($0) }.joined() as NSString + let url = URL(string: "https://block.xyz")! + for number in numbers { + let range = NSMakeRange(max(0, number - 2), 1) + let link = AttributedLabel.Link(url: url, range: range) + let accessibilityLabel = labelview.accessibilityLabel( + with: [link], + in: string as String, + linkAccessibilityLabel: "." + ) as NSString + XCTAssertNotEqual(accessibilityLabel, string) + } + } + + do { + // Test stupid ranges don't crash + let string = "Foo Bar Baz" + let url = URL(string: "https://block.xyz")! + let badRanges = [ + NSMakeRange(0, 0), + NSMakeRange(-1, 0), + NSMakeRange(0, -1), + NSMakeRange(0, 100), + NSMakeRange(100, 0), + NSMakeRange(100, -100), + ] + for range in badRanges { + let link = AttributedLabel.Link(url: url, range: range) + let accessibilityLabel = labelview.accessibilityLabel( + with: [link], + in: string as String, + linkAccessibilityLabel: "." + ) + XCTAssertEqual(accessibilityLabel, string) + } + } + + do { + // Test with emoji + let string = "🇺🇸🇨🇦🇯🇵🇫🇷" + let url = URL(string: "https://block.xyz")! + let range = NSRange(string.range(of: "🇨🇦")!, in: string) + let link = AttributedLabel.Link(url: url, range: range) + + let accessibilityLabel = labelview.accessibilityLabel( + with: [link], + in: string as String, + linkAccessibilityLabel: "." + ) + XCTAssertEqual(accessibilityLabel, "🇺🇸🇨🇦[.]🇯🇵🇫🇷") + } + } + + + func test_textContainerRects() { let lineBreakModes: [NSLineBreakMode?] = [ nil, diff --git a/CHANGELOG.md b/CHANGELOG.md index 425a1c4d2..baea9efaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Internal # Past Releases +## [4.1.1] - 2024-06-14 +- Fixed a string range bug when a closed range should be half open. -## [4.1.0] - 2024-06-04 +## [4.1.0] - 2024-06-13 ### Fixed - Fixed a bug where `AttributedLabel`'s accessibility utterance was not properly announcing links. @@ -1085,7 +1087,8 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.1.0...HEAD +[main]: https://github.com/square/Blueprint/compare/4.1.1...HEAD +[4.1.1]: https://github.com/square/Blueprint/compare/4.1.0...4.1.1 [4.1.0]: https://github.com/square/Blueprint/compare/4.0.1...4.1.0 [4.0.1]: https://github.com/square/Blueprint/compare/4.0.0...4.0.1 [4.0.0]: https://github.com/square/Blueprint/compare/3.1.0...4.0.0 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index 5bb84eb8b..85f38d46f 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.1.0) - - BlueprintUI/Tests (4.1.0) - - BlueprintUICommonControls (4.1.0): - - BlueprintUI (= 4.1.0) + - BlueprintUI (4.1.1) + - BlueprintUI/Tests (4.1.1) + - BlueprintUICommonControls (4.1.1): + - BlueprintUI (= 4.1.1) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: e3977b3657a5ce03b61b55a8e5cfdcae32c772b4 - BlueprintUICommonControls: 8c3c5a718be323baab2c01093978f2735553e035 + BlueprintUI: 7f09cc438e04105800fae3d634578a0a4d779081 + BlueprintUICommonControls: 7eb7688ca0308772a9cef0af840531be4e12f5e8 PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index 2e8504e4c..ecef4f583 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.1.0' +BLUEPRINT_VERSION ||= '4.1.1' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version')) From 72704742108801820bece0b205397be2a4911893 Mon Sep 17 00:00:00 2001 From: Nick Sillik Date: Mon, 17 Jun 2024 14:10:54 -0400 Subject: [PATCH 04/14] Replace newlines in a11y labels with spaces (#502) The built in accessibility labels do some mangling of newlines to remove them. Our implementation in `0e9041b4714cac99baa69f4b1b484503868311ba` caused regressions in snapshot and KIF testing. --- .../Sources/AttributedLabel.swift | 15 +++++++++++++-- .../Tests/Sources/AttributedLabelTests.swift | 14 ++++++++++++++ CHANGELOG.md | 2 ++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/BlueprintUICommonControls/Sources/AttributedLabel.swift b/BlueprintUICommonControls/Sources/AttributedLabel.swift index 8349a9098..a48fc5656 100644 --- a/BlueprintUICommonControls/Sources/AttributedLabel.swift +++ b/BlueprintUICommonControls/Sources/AttributedLabel.swift @@ -556,7 +556,11 @@ extension AttributedLabel { // Insert the word "link" after each link in the label. This mirrors the VoiceOver behavior when encountering a `.link` attribute. guard let localizedLinkString = linkAccessibilityLabel, - !links.isEmpty else { return string } + !links.isEmpty + else { + // We need to replace all newlines with " " + return string.removingNewlines + } var label = string // Wrap the word in [brackets] to indicate that it is a tag distinct from the content string. This is transparent to voiceover but should be helpful when the accessibility label is printed e.g. in the accessibility inspector. @@ -595,7 +599,9 @@ extension AttributedLabel { } label.insert(contentsOf: insertionString, at: insertionPoint) } - return label + + // We need to replace all newlines with " " + return label.removingNewlines } func applyLinkColors(activeLinks: [Link] = []) { @@ -849,3 +855,8 @@ extension NSTextCheckingResult.CheckingType { } } +extension String { + var removingNewlines: String { + components(separatedBy: .newlines).filter { !$0.isEmpty }.joined(separator: " ") + } +} diff --git a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift index ed58e802a..43c3985ba 100644 --- a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift +++ b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift @@ -357,6 +357,20 @@ class AttributedLabelTests: XCTestCase { compareSnapshot(of: element) } + func test_multilineAccessibility() { + let labelview = AttributedLabel.LabelView() + + for (text, expected) in [ + ("Test Test", "Test Test"), + ("Test\nTest", "Test Test"), + ("Test\n\nTest", "Test Test"), + ("\n\n\n\nTest\n\n\nTest\n\n\n", "Test Test"), + ] { + let result = labelview.accessibilityLabel(with: [], in: text, linkAccessibilityLabel: nil) + XCTAssertEqual(expected, result) + } + } + func test_linkAccessibility() { let labelview = AttributedLabel.LabelView() diff --git a/CHANGELOG.md b/CHANGELOG.md index baea9efaa..9f5469a81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fix a bug in which newlines were preserved in accessibility labels. + ### Added ### Removed From e410025f06f4e287b5dbda83200c65c7fba7fd08 Mon Sep 17 00:00:00 2001 From: Nick Sillik Date: Mon, 17 Jun 2024 14:34:58 -0400 Subject: [PATCH 05/14] Prepare 4.1.2 Release (#503) ## [4.1.2] - 2024-06-17 - Fix a bug in which newlines were preserved in accessibility labels. --- .../Sources/AttributedLabel.swift | 2 +- CHANGELOG.md | 9 ++++++--- SampleApp/Podfile.lock | 12 ++++++------ version.rb | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/BlueprintUICommonControls/Sources/AttributedLabel.swift b/BlueprintUICommonControls/Sources/AttributedLabel.swift index a48fc5656..447ebfde5 100644 --- a/BlueprintUICommonControls/Sources/AttributedLabel.swift +++ b/BlueprintUICommonControls/Sources/AttributedLabel.swift @@ -856,7 +856,7 @@ extension NSTextCheckingResult.CheckingType { } extension String { - var removingNewlines: String { + fileprivate var removingNewlines: String { components(separatedBy: .newlines).filter { !$0.isEmpty }.joined(separator: " ") } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f5469a81..96af23770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fix a bug in which newlines were preserved in accessibility labels. - ### Added ### Removed @@ -28,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Internal # Past Releases + +## [4.1.2] - 2024-06-17 +- Fix a bug in which newlines were preserved in accessibility labels. + ## [4.1.1] - 2024-06-14 - Fixed a string range bug when a closed range should be half open. @@ -1089,7 +1091,8 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.1.1...HEAD +[main]: https://github.com/square/Blueprint/compare/4.1.2...HEAD +[4.1.1]: https://github.com/square/Blueprint/compare/4.1.1...4.1.2 [4.1.1]: https://github.com/square/Blueprint/compare/4.1.0...4.1.1 [4.1.0]: https://github.com/square/Blueprint/compare/4.0.1...4.1.0 [4.0.1]: https://github.com/square/Blueprint/compare/4.0.0...4.0.1 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index 85f38d46f..dd22abaeb 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.1.1) - - BlueprintUI/Tests (4.1.1) - - BlueprintUICommonControls (4.1.1): - - BlueprintUI (= 4.1.1) + - BlueprintUI (4.1.2) + - BlueprintUI/Tests (4.1.2) + - BlueprintUICommonControls (4.1.2): + - BlueprintUI (= 4.1.2) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: 7f09cc438e04105800fae3d634578a0a4d779081 - BlueprintUICommonControls: 7eb7688ca0308772a9cef0af840531be4e12f5e8 + BlueprintUI: a05960580dbdbb9aa5ff4658dd969846dc3b95a7 + BlueprintUICommonControls: 119616850083675a7abcbf92021051ace2dd4ed9 PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index ecef4f583..ee4c399ee 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.1.1' +BLUEPRINT_VERSION ||= '4.1.2' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version')) From 691f554c6ef703465409daf78a189e9687298d79 Mon Sep 17 00:00:00 2001 From: Kyle Van Essen Date: Tue, 25 Jun 2024 17:26:14 -0700 Subject: [PATCH 06/14] Label and AttributedLabel now support accessibilityValue (#504) We support hint, but not value. So, adding value too! --- .../Sources/AttributedLabel.swift | 19 +++++++++++++------ BlueprintUICommonControls/Sources/Label.swift | 7 +++++++ .../Tests/Sources/AttributedLabelTests.swift | 14 ++++++++++++++ CHANGELOG.md | 2 ++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/BlueprintUICommonControls/Sources/AttributedLabel.swift b/BlueprintUICommonControls/Sources/AttributedLabel.swift index 447ebfde5..ea91fc2f9 100644 --- a/BlueprintUICommonControls/Sources/AttributedLabel.swift +++ b/BlueprintUICommonControls/Sources/AttributedLabel.swift @@ -77,6 +77,12 @@ public struct AttributedLabel: Element, Hashable { /// A set of accessibility traits that should be applied to the label, these will be merged with any existing traits. public var accessibilityTraits: Set? + /// A localized string that represents the current value of the accessibility element. + /// + /// The value is a localized string that contains the current value of an element. + /// For example, the value of a slider might be 9.5 or 35% and the value of a text field is the text it contains. + public var accessibilityValue: String? + /// A localized string that describes the result of performing an action on the element, when the result is non-obvious. public var accessibilityHint: String? @@ -249,13 +255,14 @@ extension AttributedLabel { if !isMeasuring { updateFontFitting(with: model) - } - isAccessibilityElement = model.isAccessibilityElement - accessibilityHint = model.accessibilityHint - updateAccessibilityTraits(with: model) - accessibilityCustomActions = model.accessibilityCustomActions.map { action in - UIAccessibilityCustomAction(name: action.name) { _ in action.onActivation() } + isAccessibilityElement = model.isAccessibilityElement + accessibilityHint = model.accessibilityHint + accessibilityValue = model.accessibilityValue + updateAccessibilityTraits(with: model) + accessibilityCustomActions = model.accessibilityCustomActions.map { action in + UIAccessibilityCustomAction(name: action.name) { _ in action.onActivation() } + } } urlHandler = environment.urlHandler diff --git a/BlueprintUICommonControls/Sources/Label.swift b/BlueprintUICommonControls/Sources/Label.swift index 5a3ff5484..803d9d3c7 100644 --- a/BlueprintUICommonControls/Sources/Label.swift +++ b/BlueprintUICommonControls/Sources/Label.swift @@ -57,6 +57,12 @@ public struct Label: ProxyElement { /// Determines if the label should be included when navigating the UI via accessibility. public var isAccessibilityElement = true + /// A localized string that represents the current value of the accessibility element. + /// + /// The value is a localized string that contains the current value of an element. + /// For example, the value of a slider might be 9.5 or 35% and the value of a text field is the text it contains. + public var accessibilityValue: String? + /// A localized string that describes the result of performing an action on the element, when the result is non-obvious. public var accessibilityHint: String? @@ -102,6 +108,7 @@ public struct Label: ProxyElement { label.numberOfLines = numberOfLines label.shadow = shadow label.isAccessibilityElement = isAccessibilityElement + label.accessibilityValue = accessibilityValue label.accessibilityHint = accessibilityHint label.accessibilityTraits = accessibilityTraits label.accessibilityCustomActions = accessibilityCustomActions diff --git a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift index 43c3985ba..b681550d7 100644 --- a/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift +++ b/BlueprintUICommonControls/Tests/Sources/AttributedLabelTests.swift @@ -371,6 +371,20 @@ class AttributedLabelTests: XCTestCase { } } + func test_attributedValue() throws { + let view = BlueprintView() + + view.element = AttributedLabel(attributedText: NSAttributedString(string: "Some string with stuff")) { + $0.accessibilityValue = "A value" + } + + view.layoutIfNeeded() + + let labelView = try XCTUnwrap(view.firstSubview(ofType: AttributedLabel.LabelView.self)) + + XCTAssertEqual(labelView.accessibilityValue, "A value") + } + func test_linkAccessibility() { let labelview = AttributedLabel.LabelView() diff --git a/CHANGELOG.md b/CHANGELOG.md index 96af23770..1aa0978cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `Label` and `AttributedLabel` now support `accessibilityValue`. + ### Removed ### Changed From 719ab738eaf7a5128f5632f5bd761af626c50a4d Mon Sep 17 00:00:00 2001 From: Kyle Van Essen Date: Tue, 25 Jun 2024 17:43:41 -0700 Subject: [PATCH 07/14] Prepare 4.2.0 (#505) --- CHANGELOG.md | 13 +++++++++---- SampleApp/Podfile.lock | 12 ++++++------ version.rb | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa0978cc..215f2c761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `Label` and `AttributedLabel` now support `accessibilityValue`. - ### Removed ### Changed @@ -29,6 +27,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Past Releases +## [4.2.0] - 2024-06-25 + +### Added + +- `Label` and `AttributedLabel` now support `accessibilityValue`. + ## [4.1.2] - 2024-06-17 - Fix a bug in which newlines were preserved in accessibility labels. @@ -1093,8 +1097,9 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.1.2...HEAD -[4.1.1]: https://github.com/square/Blueprint/compare/4.1.1...4.1.2 +[main]: https://github.com/square/Blueprint/compare/4.2.0...HEAD +[4.2.0]: https://github.com/square/Blueprint/compare/4.1.2...4.2.0 +[4.1.2]: https://github.com/square/Blueprint/compare/4.1.1...4.1.2 [4.1.1]: https://github.com/square/Blueprint/compare/4.1.0...4.1.1 [4.1.0]: https://github.com/square/Blueprint/compare/4.0.1...4.1.0 [4.0.1]: https://github.com/square/Blueprint/compare/4.0.0...4.0.1 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index dd22abaeb..c83bb2680 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.1.2) - - BlueprintUI/Tests (4.1.2) - - BlueprintUICommonControls (4.1.2): - - BlueprintUI (= 4.1.2) + - BlueprintUI (4.2.0) + - BlueprintUI/Tests (4.2.0) + - BlueprintUICommonControls (4.2.0): + - BlueprintUI (= 4.2.0) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: a05960580dbdbb9aa5ff4658dd969846dc3b95a7 - BlueprintUICommonControls: 119616850083675a7abcbf92021051ace2dd4ed9 + BlueprintUI: 895a33dcf93c2c4eed07e348c01e72178d45833f + BlueprintUICommonControls: 465528dab742ffa509ebe782d8f071309de952f3 PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index ee4c399ee..705fa3bb5 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.1.2' +BLUEPRINT_VERSION ||= '4.2.0' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version')) From 12262ff40b5a95fe5d24e2182ee784bc11db17a4 Mon Sep 17 00:00:00 2001 From: Steven Grosmark Date: Thu, 1 Aug 2024 17:04:20 -0400 Subject: [PATCH 08/14] Make public the UIBezierPath helper using Box.CornerStyle --- .../Sources/Internal/UIBezierPath+Extensions.swift | 2 +- CHANGELOG.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift b/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift index 54865cd11..2444a045c 100644 --- a/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift +++ b/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift @@ -3,7 +3,7 @@ import UIKit extension UIBezierPath { - convenience init( + public convenience init( rect: CGRect, corners: Box.CornerStyle ) { diff --git a/CHANGELOG.md b/CHANGELOG.md index 215f2c761..2bb9d14b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Made public the `UIBezierPath` convenience init that uses a `Box.CornerStyle`. + ### Removed ### Changed From fca1db62b157bdbdff97ed1c4124041c5d1fcbfb Mon Sep 17 00:00:00 2001 From: Steven Grosmark Date: Fri, 2 Aug 2024 11:18:09 -0400 Subject: [PATCH 09/14] Prepare 4.2.1 (#507) --- CHANGELOG.md | 11 ++++++++--- SampleApp/Podfile.lock | 12 ++++++------ version.rb | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb9d14b7..66d734d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Made public the `UIBezierPath` convenience init that uses a `Box.CornerStyle`. - ### Removed ### Changed @@ -29,6 +27,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Past Releases +## [4.2.1] - 2024-08-02 + +### Added + +- Made public the `UIBezierPath` convenience init that uses a `Box.CornerStyle`. + ## [4.2.0] - 2024-06-25 ### Added @@ -1099,7 +1103,8 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.2.0...HEAD +[main]: https://github.com/square/Blueprint/compare/4.2.1...HEAD +[4.2.1]: https://github.com/square/Blueprint/compare/4.2.0...4.2.1 [4.2.0]: https://github.com/square/Blueprint/compare/4.1.2...4.2.0 [4.1.2]: https://github.com/square/Blueprint/compare/4.1.1...4.1.2 [4.1.1]: https://github.com/square/Blueprint/compare/4.1.0...4.1.1 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index c83bb2680..65314288e 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.2.0) - - BlueprintUI/Tests (4.2.0) - - BlueprintUICommonControls (4.2.0): - - BlueprintUI (= 4.2.0) + - BlueprintUI (4.2.1) + - BlueprintUI/Tests (4.2.1) + - BlueprintUICommonControls (4.2.1): + - BlueprintUI (= 4.2.1) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: 895a33dcf93c2c4eed07e348c01e72178d45833f - BlueprintUICommonControls: 465528dab742ffa509ebe782d8f071309de952f3 + BlueprintUI: b1174cecb229b8f3357fb70e99b7d548b3c90586 + BlueprintUICommonControls: 555c04035aeaf509d1c459f08af33e89d3594b85 PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index 705fa3bb5..653cb2b4e 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.2.0' +BLUEPRINT_VERSION ||= '4.2.1' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version')) From 73ba67c6edabe0cecca1f1c2612f9c2f57adfb1c Mon Sep 17 00:00:00 2001 From: Steven Grosmark Date: Wed, 14 Aug 2024 09:41:28 -0400 Subject: [PATCH 10/14] Unnest Box.CornerStyle (#508) Since `Box.CornerStyle` is used for other things besides specifying the corners of a `Box`, this PR moves the `CornerStyle` type to the root of the framework. To maintain compatibility, a typealias is added to `Box`, so consumers can continue to use `Box.CornerRadius`. --- .../Sources/AccessibilityElement.swift | 8 +-- BlueprintUICommonControls/Sources/Box.swift | 65 +----------------- .../Sources/CornerStyle.swift | 67 +++++++++++++++++++ .../Internal/UIBezierPath+Extensions.swift | 2 +- CHANGELOG.md | 2 + 5 files changed, 75 insertions(+), 69 deletions(-) create mode 100644 BlueprintUICommonControls/Sources/CornerStyle.swift diff --git a/BlueprintUICommonControls/Sources/AccessibilityElement.swift b/BlueprintUICommonControls/Sources/AccessibilityElement.swift index 391b46835..0decb11f1 100644 --- a/BlueprintUICommonControls/Sources/AccessibilityElement.swift +++ b/BlueprintUICommonControls/Sources/AccessibilityElement.swift @@ -13,7 +13,7 @@ public struct AccessibilityElement: Element { public var identifier: String? public var traits: Set public var accessibilityFrameSize: CGSize? - public var accessibilityFrameCornerStyle: Box.CornerStyle + public var accessibilityFrameCornerStyle: CornerStyle public var wrappedElement: Element /// Used to provide custom behaviour when activated by voiceover. This will override the default behavior of issuing a tap event at the accessibility activation point. @@ -34,7 +34,7 @@ public struct AccessibilityElement: Element { hint: String? = nil, identifier: String? = nil, accessibilityFrameSize: CGSize? = nil, - accessibilityFrameCornerStyle: Box.CornerStyle = .square, + accessibilityFrameCornerStyle: CornerStyle = .square, customActions: [AccessibilityElement.CustomAction] = [], customContent: [AccessibilityElement.CustomContent] = [], wrapping element: Element, @@ -92,7 +92,7 @@ public struct AccessibilityElement: Element { private final class AccessibilityView: UIView, AXCustomContentProvider { var accessibilityFrameSize: CGSize? - var accessibilityFrameCornerStyle: Box.CornerStyle = .square + var accessibilityFrameCornerStyle: CornerStyle = .square var accessibilityCustomContent: [AXCustomContent]! = [] // The exclamation `!` is in the protodol definition and required. var increment: (() -> Void)? @@ -175,7 +175,7 @@ extension Element { hint: String? = nil, identifier: String? = nil, accessibilityFrameSize: CGSize? = nil, - accessibilityFrameCornerStyle: Box.CornerStyle = .square, + accessibilityFrameCornerStyle: CornerStyle = .square, customActions: [AccessibilityElement.CustomAction] = [], customContent: [AccessibilityElement.CustomContent] = [] ) -> AccessibilityElement { diff --git a/BlueprintUICommonControls/Sources/Box.swift b/BlueprintUICommonControls/Sources/Box.swift index f26c6e58e..804c64b0c 100644 --- a/BlueprintUICommonControls/Sources/Box.swift +++ b/BlueprintUICommonControls/Sources/Box.swift @@ -129,70 +129,7 @@ public struct Box: Element { extension Box { - public enum CornerStyle: Equatable { - case square - case capsule - case rounded(radius: CGFloat, corners: Corners = .all) - - public struct Corners: OptionSet, Equatable { - public let rawValue: UInt8 - - public init(rawValue: UInt8) { - self.rawValue = rawValue - } - - public static let topLeft = Corners(rawValue: 1) - public static let topRight = Corners(rawValue: 1 << 1) - public static let bottomLeft = Corners(rawValue: 1 << 2) - public static let bottomRight = Corners(rawValue: 1 << 3) - - public static let all: Corners = [.topLeft, .topRight, .bottomLeft, .bottomRight] - public static let top: Corners = [.topRight, .topLeft] - public static let left: Corners = [.topLeft, .bottomLeft] - public static let bottom: Corners = [.bottomLeft, .bottomRight] - public static let right: Corners = [.topRight, .bottomRight] - - var toCACornerMask: CACornerMask { - var mask: CACornerMask = [] - if contains(.topLeft) { - mask.update(with: .layerMinXMinYCorner) - } - - if contains(.topRight) { - mask.update(with: .layerMaxXMinYCorner) - } - - if contains(.bottomLeft) { - mask.update(with: .layerMinXMaxYCorner) - } - - if contains(.bottomRight) { - mask.update(with: .layerMaxXMaxYCorner) - } - return mask - } - - var toUIRectCorner: UIRectCorner { - var rectCorner: UIRectCorner = [] - if contains(.topLeft) { - rectCorner.update(with: .topLeft) - } - - if contains(.topRight) { - rectCorner.update(with: .topRight) - } - - if contains(.bottomLeft) { - rectCorner.update(with: .bottomLeft) - } - - if contains(.bottomRight) { - rectCorner.update(with: .bottomRight) - } - return rectCorner - } - } - } + public typealias CornerStyle = BlueprintUICommonControls.CornerStyle /// Specifies the curve style when showing rounded corners on a `Box`. public enum CornerCurve: Equatable { diff --git a/BlueprintUICommonControls/Sources/CornerStyle.swift b/BlueprintUICommonControls/Sources/CornerStyle.swift new file mode 100644 index 000000000..7ed3ca664 --- /dev/null +++ b/BlueprintUICommonControls/Sources/CornerStyle.swift @@ -0,0 +1,67 @@ +import BlueprintUI +import UIKit + +public enum CornerStyle: Equatable { + case square + case capsule + case rounded(radius: CGFloat, corners: Corners = .all) + + public struct Corners: OptionSet, Equatable { + public let rawValue: UInt8 + + public init(rawValue: UInt8) { + self.rawValue = rawValue + } + + public static let topLeft = Corners(rawValue: 1) + public static let topRight = Corners(rawValue: 1 << 1) + public static let bottomLeft = Corners(rawValue: 1 << 2) + public static let bottomRight = Corners(rawValue: 1 << 3) + + public static let all: Corners = [.topLeft, .topRight, .bottomLeft, .bottomRight] + public static let top: Corners = [.topRight, .topLeft] + public static let left: Corners = [.topLeft, .bottomLeft] + public static let bottom: Corners = [.bottomLeft, .bottomRight] + public static let right: Corners = [.topRight, .bottomRight] + + var toCACornerMask: CACornerMask { + var mask: CACornerMask = [] + if contains(.topLeft) { + mask.update(with: .layerMinXMinYCorner) + } + + if contains(.topRight) { + mask.update(with: .layerMaxXMinYCorner) + } + + if contains(.bottomLeft) { + mask.update(with: .layerMinXMaxYCorner) + } + + if contains(.bottomRight) { + mask.update(with: .layerMaxXMaxYCorner) + } + return mask + } + + var toUIRectCorner: UIRectCorner { + var rectCorner: UIRectCorner = [] + if contains(.topLeft) { + rectCorner.update(with: .topLeft) + } + + if contains(.topRight) { + rectCorner.update(with: .topRight) + } + + if contains(.bottomLeft) { + rectCorner.update(with: .bottomLeft) + } + + if contains(.bottomRight) { + rectCorner.update(with: .bottomRight) + } + return rectCorner + } + } +} diff --git a/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift b/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift index 2444a045c..49508cbbe 100644 --- a/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift +++ b/BlueprintUICommonControls/Sources/Internal/UIBezierPath+Extensions.swift @@ -5,7 +5,7 @@ extension UIBezierPath { public convenience init( rect: CGRect, - corners: Box.CornerStyle + corners: CornerStyle ) { switch corners { case .square: diff --git a/CHANGELOG.md b/CHANGELOG.md index 66d734d2d..80261cc1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Moved `CornerStyle` out of the `Box` namespace, and is now a root type in `BlueprintUICommonControls`. `Box.CornerStyle` is still available as a typealias. + ### Deprecated ### Security From ef1869fe7c14932a61e75c4b7029d80c8be925f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 20:38:38 +0000 Subject: [PATCH 11/14] Bump rexml from 3.2.8 to 3.3.6 Bumps [rexml](https://github.com/ruby/rexml) from 3.2.8 to 3.3.6. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.8...v3.3.6) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 43d31826b..5eb107e79 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,8 +97,8 @@ GEM open4 (1.3.4) public_suffix (4.0.7) redcarpet (3.6.0) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.6) + strscan rouge (4.2.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -113,13 +113,13 @@ GEM concurrent-ruby (~> 1.0) xcinvoke (0.3.0) liferaft (~> 0.0.6) - xcodeproj (1.23.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) PLATFORMS arm64-darwin-22 From 84865aee4b89acddf38fd8264e578ddaad393a50 Mon Sep 17 00:00:00 2001 From: maxg-square Date: Tue, 17 Sep 2024 16:13:30 -0700 Subject: [PATCH 12/14] Bump checkout and upload-artifacts (#512) Update to current version of checkout and upload-artifacts --- .github/workflows/docs.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tests.yaml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a1d9cdf9c..25a910e9c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Read env run: cat .github/workflows/env.properties >> $GITHUB_ENV diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2363acec7..89ab28de3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Read env run: cat .github/workflows/env.properties >> $GITHUB_ENV diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 946d67666..8a4c520a3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -31,7 +31,7 @@ jobs: installation_required: false steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Read env run: cat .github/workflows/env.properties >> $GITHUB_ENV @@ -56,7 +56,7 @@ jobs: git ls-files -mo BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages | xargs tar -cvf snapshot_changes_${{ matrix.sdk }}.tar - name: Archive snapshot changes - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: ${{ failure() }} with: name: snapshot_changes_${{ matrix.sdk }} @@ -69,7 +69,7 @@ jobs: runs-on: macos-13-xlarge steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Read env run: cat .github/workflows/env.properties >> $GITHUB_ENV From 3b88ea691d4a3606be58a2590e883963b59372ca Mon Sep 17 00:00:00 2001 From: Kyle Van Essen Date: Wed, 18 Sep 2024 11:17:36 -0700 Subject: [PATCH 13/14] Add passThroughTouches to BlueprintView, PassthroughView (#511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, Blueprint will eat any touches that are meant for views behind it – in particular relevant if you're layering them in the z-index and the one on "top" is largely visually transparent. --- .../Sources/BlueprintView/BlueprintView.swift | 27 +++++++++++++++++-- .../Sources/Internal/PassthroughView.swift | 12 ++++++--- CHANGELOG.md | 2 ++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/BlueprintUI/Sources/BlueprintView/BlueprintView.swift b/BlueprintUI/Sources/BlueprintView/BlueprintView.swift index 09959e076..3b978ed03 100644 --- a/BlueprintUI/Sources/BlueprintView/BlueprintView.swift +++ b/BlueprintUI/Sources/BlueprintView/BlueprintView.swift @@ -118,6 +118,16 @@ public final class BlueprintView: UIView { /// Provides performance metrics about the duration of layouts, updates, etc. public weak var metricsDelegate: BlueprintViewMetricsDelegate? = nil + /// Defaults to `false`. If enabled, Blueprint will pass through any touches + /// not recieved by an element to the view hierarchy behind the `BlueprintView`. + public var passThroughTouches: Bool = false { + didSet { + if oldValue != passThroughTouches { + setNeedsViewHierarchyUpdate() + } + } + } + private var isVisible: Bool = false { didSet { switch (oldValue, isVisible) { @@ -141,7 +151,7 @@ public final class BlueprintView: UIView { rootController = NativeViewController( node: NativeViewNode( - content: UIView.describe { _ in }, + content: PassthroughView.describe { _ in }, // Because no layout update occurs here, passing an empty environment is fine; // the correct environment will be passed during update. environment: .empty, @@ -327,6 +337,17 @@ public final class BlueprintView: UIView { setNeedsViewHierarchyUpdate() } + /// Ignore any touches on this view and (pass through) by returning nil if the default `hitTest` implementation returns this view. + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let result = super.hitTest(point, with: event) + + if passThroughTouches { + return result == self ? nil : result + } else { + return result + } + } + /// Clears any sizing caches, invalidates the `intrinsicContentSize` of the /// view, and marks the view as needing a layout. private func setNeedsViewHierarchyUpdate() { @@ -391,7 +412,9 @@ public final class BlueprintView: UIView { rootController.view.frame = bounds var rootNode = NativeViewNode( - content: UIView.describe { _ in }, + content: PassthroughView.describe { [weak self] config in + config[\.passThroughTouches] = self?.passThroughTouches ?? false + }, environment: environment, layoutAttributes: LayoutAttributes(frame: rootFrame), children: viewNodes diff --git a/BlueprintUI/Sources/Internal/PassthroughView.swift b/BlueprintUI/Sources/Internal/PassthroughView.swift index a791da7e7..e1cc1162f 100644 --- a/BlueprintUI/Sources/Internal/PassthroughView.swift +++ b/BlueprintUI/Sources/Internal/PassthroughView.swift @@ -8,10 +8,16 @@ import UIKit CATransformLayer.self } - /// Ignore any touches on this view and (pass through) by returning nil if the - /// default `hitTest` implementation returns this view. + public var passThroughTouches: Bool = true + + /// Ignore any touches on this view and (pass through) by returning nil if the default `hitTest` implementation returns this view. public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let result = super.hitTest(point, with: event) - return result == self ? nil : result + + if passThroughTouches { + return result == self ? nil : result + } else { + return result + } } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 80261cc1a..7cfcc6131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `BlueprintView` will now pass through touches to views lower in the view hierarchy if `passThroughTouches` is true. + ### Removed ### Changed From d1fe857372e048b24ad99e1fe8b8fd49cfe0dce2 Mon Sep 17 00:00:00 2001 From: Kyle Van Essen Date: Wed, 18 Sep 2024 12:30:57 -0700 Subject: [PATCH 14/14] Prepare version 4.3.0 (#513) --- CHANGELOG.md | 17 ++++++++++++----- SampleApp/Podfile.lock | 12 ++++++------ version.rb | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cfcc6131..a2f8d843e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,14 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `BlueprintView` will now pass through touches to views lower in the view hierarchy if `passThroughTouches` is true. - ### Removed ### Changed -- Moved `CornerStyle` out of the `Box` namespace, and is now a root type in `BlueprintUICommonControls`. `Box.CornerStyle` is still available as a typealias. - ### Deprecated ### Security @@ -31,6 +27,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Past Releases +## [4.3.0] - 2024-09-18 + +### Added + +- `BlueprintView` will now pass through touches to views lower in the view hierarchy if `passThroughTouches` is true. + +### Changed + +- Moved `CornerStyle` out of the `Box` namespace, and is now a root type in `BlueprintUICommonControls`. `Box.CornerStyle` is still available as a typealias. + ## [4.2.1] - 2024-08-02 ### Added @@ -1107,7 +1113,8 @@ searchField - First stable release. -[main]: https://github.com/square/Blueprint/compare/4.2.1...HEAD +[main]: https://github.com/square/Blueprint/compare/4.3.0...HEAD +[4.3.0]: https://github.com/square/Blueprint/compare/4.2.1...4.3.0 [4.2.1]: https://github.com/square/Blueprint/compare/4.2.0...4.2.1 [4.2.0]: https://github.com/square/Blueprint/compare/4.1.2...4.2.0 [4.1.2]: https://github.com/square/Blueprint/compare/4.1.1...4.1.2 diff --git a/SampleApp/Podfile.lock b/SampleApp/Podfile.lock index 65314288e..b953e9405 100644 --- a/SampleApp/Podfile.lock +++ b/SampleApp/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - BlueprintUI (4.2.1) - - BlueprintUI/Tests (4.2.1) - - BlueprintUICommonControls (4.2.1): - - BlueprintUI (= 4.2.1) + - BlueprintUI (4.3.0) + - BlueprintUI/Tests (4.3.0) + - BlueprintUICommonControls (4.3.0): + - BlueprintUI (= 4.3.0) DEPENDENCIES: - BlueprintUI (from `../BlueprintUI.podspec`) @@ -16,8 +16,8 @@ EXTERNAL SOURCES: :path: "../BlueprintUICommonControls.podspec" SPEC CHECKSUMS: - BlueprintUI: b1174cecb229b8f3357fb70e99b7d548b3c90586 - BlueprintUICommonControls: 555c04035aeaf509d1c459f08af33e89d3594b85 + BlueprintUI: be852bd1c895f5405af2c75a6aa8bef0dacf41a8 + BlueprintUICommonControls: 41b66f55f4bbc8454e0e6fa01dbbabdd499accba PODFILE CHECKSUM: 1cffac4623851f31dc42270ba99701e3825e6d67 diff --git a/version.rb b/version.rb index 653cb2b4e..75edce2cd 100644 --- a/version.rb +++ b/version.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -BLUEPRINT_VERSION ||= '4.2.1' +BLUEPRINT_VERSION ||= '4.3.0' SWIFT_VERSION ||= File.read(File.join(__dir__, '.swift-version'))