@@ -58,6 +58,9 @@ public struct TextState: Equatable, Hashable {
5858 fileprivate let storage : Storage
5959
6060 fileprivate enum Modifier : Equatable , Hashable {
61+ case accessibilityHeading( AccessibilityHeadingLevel )
62+ case accessibilityLabel( TextState )
63+ case accessibilityTextContentType( AccessibilityTextContentType )
6164 case baselineOffset( CGFloat )
6265 case bold
6366 case font( Font ? )
@@ -122,6 +125,8 @@ public struct TextState: Equatable, Hashable {
122125 }
123126}
124127
128+ // MARK: - API
129+
125130extension TextState {
126131 public init ( verbatim content: String ) {
127132 self . storage = . verbatim( content)
@@ -206,6 +211,82 @@ extension TextState {
206211 }
207212}
208213
214+ // MARK: Accessibility
215+
216+ extension TextState {
217+ public enum AccessibilityTextContentType : String , Equatable , Hashable {
218+ case console, fileSystem, messaging, narrative, plain, sourceCode, spreadsheet, wordProcessing
219+
220+ #if compiler(>=5.5.1)
221+ @available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
222+ var toSwiftUI : SwiftUI . AccessibilityTextContentType {
223+ switch self {
224+ case . console: return . console
225+ case . fileSystem: return . fileSystem
226+ case . messaging: return . messaging
227+ case . narrative: return . narrative
228+ case . plain: return . plain
229+ case . sourceCode: return . sourceCode
230+ case . spreadsheet: return . spreadsheet
231+ case . wordProcessing: return . wordProcessing
232+ }
233+ }
234+ #endif
235+ }
236+
237+ public enum AccessibilityHeadingLevel : String , Equatable , Hashable {
238+ case h1, h2, h3, h4, h5, h6, unspecified
239+
240+ #if compiler(>=5.5.1)
241+ @available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
242+ var toSwiftUI : SwiftUI . AccessibilityHeadingLevel {
243+ switch self {
244+ case . h1: return . h1
245+ case . h2: return . h2
246+ case . h3: return . h3
247+ case . h4: return . h4
248+ case . h5: return . h5
249+ case . h6: return . h6
250+ case . unspecified: return . unspecified
251+ }
252+ }
253+ #endif
254+ }
255+ }
256+
257+ @available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
258+ extension TextState {
259+ public func accessibilityHeading( _ headingLevel: AccessibilityHeadingLevel ) -> Self {
260+ var `self` = self
261+ `self`. modifiers. append ( . accessibilityHeading( headingLevel) )
262+ return `self`
263+ }
264+
265+ public func accessibilityLabel( _ string: String ) -> Self {
266+ var `self` = self
267+ `self`. modifiers. append ( . accessibilityLabel( . init( string) ) )
268+ return `self`
269+ }
270+
271+ public func accessibilityLabel< S: StringProtocol > ( _ string: S ) -> Self {
272+ var `self` = self
273+ `self`. modifiers. append ( . accessibilityLabel( . init( string) ) )
274+ return `self`
275+ }
276+
277+ public func accessibilityLabel( _ key: LocalizedStringKey , tableName: String ? = nil , bundle: Bundle ? = nil , comment: StaticString ? = nil ) -> Self {
278+ var `self` = self
279+ `self`. modifiers. append ( . accessibilityLabel( . init( key, tableName: tableName, bundle: bundle, comment: comment) ) )
280+ return `self`
281+ }
282+
283+ public func accessibilityTextContentType( _ type: AccessibilityTextContentType ) -> Self {
284+ var `self` = self
285+ `self`. modifiers. append ( . accessibilityTextContentType( type) )
286+ return `self`
287+ }
288+ }
289+
209290extension Text {
210291 public init ( _ state: TextState ) {
211292 let text : Text
@@ -219,6 +300,39 @@ extension Text {
219300 }
220301 self = state. modifiers. reduce ( text) { text, modifier in
221302 switch modifier {
303+ #if compiler(>=5.5.1)
304+ case let . accessibilityHeading( level) :
305+ if #available( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * ) {
306+ return text. accessibilityHeading ( level. toSwiftUI)
307+ } else {
308+ return text
309+ }
310+ case let . accessibilityLabel( value) :
311+ if #available( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * ) {
312+ switch value. storage {
313+ case let . verbatim( string) :
314+ return text. accessibilityLabel ( string)
315+ case let . localized( key, tableName, bundle, comment) :
316+ return text. accessibilityLabel ( Text ( key, tableName: tableName, bundle: bundle, comment: comment) )
317+ case . concatenated( _, _) :
318+ assertionFailure ( " `.accessibilityLabel` does not support contcatenated `TextState` " )
319+ return text
320+ }
321+ } else {
322+ return text
323+ }
324+ case let . accessibilityTextContentType( type) :
325+ if #available( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * ) {
326+ return text. accessibilityTextContentType ( type. toSwiftUI)
327+ } else {
328+ return text
329+ }
330+ #else
331+ case . accessibilityHeading,
332+ . accessibilityLabel,
333+ . accessibilityTextContentType:
334+ return text
335+ #endif
222336 case let . baselineOffset( baselineOffset) :
223337 return text. baselineOffset ( baselineOffset)
224338 case . bold:
@@ -308,6 +422,8 @@ extension LocalizedStringKey {
308422 }
309423}
310424
425+ // MARK: - CustomDumpRepresentable
426+
311427extension TextState : CustomDumpRepresentable {
312428 public var customDumpValue : Any {
313429 func dumpHelp( _ textState: Self ) -> String {
@@ -322,6 +438,15 @@ extension TextState: CustomDumpRepresentable {
322438 }
323439 for modifier in textState. modifiers {
324440 switch modifier {
441+ case let . accessibilityHeading( headingLevel) :
442+ let tag = " accessibility-heading-level "
443+ output = " < \( tag) = \( headingLevel. rawValue) > \( output) </ \( tag) > "
444+ case let . accessibilityLabel( value) :
445+ let tag = " accessibility-label "
446+ output = " < \( tag) = \( dumpHelp ( value) ) > \( output) </ \( tag) > "
447+ case let . accessibilityTextContentType( type) :
448+ let tag = " accessibility-text-content-type "
449+ output = " < \( tag) = \( type. rawValue) > \( output) </ \( tag) > "
325450 case let . baselineOffset( baselineOffset) :
326451 output = " <baseline-offset= \( baselineOffset) > \( output) </baseline-offset> "
327452 case . bold, . fontWeight( . some( . bold) ) :
0 commit comments