{"id":2040,"url":"https://github.com/malcommac/SwiftRichString","last_synced_at":"2025-08-06T14:32:58.737Z","repository":{"id":39615519,"uuid":"75933542","full_name":"malcommac/SwiftRichString","owner":"malcommac","description":"👩‍🎨 Elegant Attributed String composition in Swift sauce","archived":false,"fork":false,"pushed_at":"2023-07-18T15:28:52.000Z","size":3809,"stargazers_count":3149,"open_issues_count":41,"forks_count":208,"subscribers_count":55,"default_branch":"master","last_synced_at":"2025-07-31T03:54:13.667Z","etag":null,"topics":["attributedstring","auto-layout","dynamic-type","nsattributedstring","swift","swift-library","text","text-formatting","typography","xml-parsing"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malcommac.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":"malcommac","custom":"https://www.paypal.com/paypalme2/danielemargutti"}},"created_at":"2016-12-08T11:57:24.000Z","updated_at":"2025-07-26T04:19:52.000Z","dependencies_parsed_at":"2023-02-17T19:30:25.829Z","dependency_job_id":"689cbe37-3289-4919-b78f-45e08aec2282","html_url":"https://github.com/malcommac/SwiftRichString","commit_stats":{"total_commits":245,"total_committers":17,"mean_commits":"14.411764705882353","dds":"0.15102040816326534","last_synced_commit":"e0b72d5c96968d7802856d2be096202c9798e8d1"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/malcommac/SwiftRichString","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FSwiftRichString","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FSwiftRichString/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FSwiftRichString/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FSwiftRichString/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malcommac","download_url":"https://codeload.github.com/malcommac/SwiftRichString/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FSwiftRichString/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269005881,"owners_count":24343406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-06T02:00:09.910Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attributedstring","auto-layout","dynamic-type","nsattributedstring","swift","swift-library","text","text-formatting","typography","xml-parsing"],"created_at":"2024-01-05T20:16:01.913Z","updated_at":"2025-08-06T14:32:58.285Z","avatar_url":"https://github.com/malcommac.png","language":"Swift","readme":"\u003cp align=\"center\" \u003e\n  \u003cimg src=\"banner.png\" width=300px alt=\"SwiftLocation\" title=\"SwiftLocation\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003e Elegant Attributed String composition in Swift sauce\u003c/strong\u003e\u003c/p\u003e\n\nSwiftRichString is a lightweight library which allows to create and manipulate attributed strings easily both in iOS, macOS, tvOS and even watchOS.\nIt provides convenient way to store styles you can reuse in your app's UI elements, allows complex tag-based strings rendering and also includes integration with Interface Builder.\n\n## Main Features\n\n|  \t| Features Highlights \t|\n|---\t|---------------------------------------------------------------------------------\t|\n| 🦄 \t| Easy styling and typography managment with coincise declarative syntax\t|\n| 🏞 \t| Attach local images (lazy/static) and remote images inside text \t|\n| 🧬 \t| Fast \u0026 high customizable XML/HTML tagged string rendering \t|\n| 🌟 \t| Apply text transforms within styles\t|\n| 📐 \t| Native support for iOS 11 Dynamic Type\t|\n| 🖇 \t| Support for Swift 5.1's function builder to compose strings\t|\n| ⏱ \t| Compact code base with no external dependencies. \t|\n| 🐦 \t| Fully made in Swift 5 from Swift ❥ lovers \t|\n\n### Easy Styling\n\n```swift\nlet style = Style {\n\t$0.font = SystemFonts.AmericanTypewriter.font(size: 25) // just pass a string, one of the SystemFonts or an UIFont\n\t$0.color = \"#0433FF\" // you can use UIColor or HEX string!\n\t$0.underline = (.patternDot, UIColor.red)\n\t$0.alignment = .center\n}\nlet attributedText = \"Hello World!\".set(style: style) // et voilà!\n```\n\n### XML/HTML tag based rendering\nSwiftRichString allows you to render complex strings by parsing text's tags: each style will be identified by an unique name (used inside the tag) and you can create a `StyleXML` (was `StyleGroup`) which allows you to encapsulate all of them and reuse as you need (clearly you can register it globally).\n\n```swift\n// Create your own styles\n\nlet normal = Style {\n\t$0.font = SystemFonts.Helvetica_Light.font(size: 15)\n}\n\t\t\nlet bold = Style {\n\t$0.font = SystemFonts.Helvetica_Bold.font(size: 20)\n\t$0.color = UIColor.red\n\t$0.backColor = UIColor.yellow\n}\n\t\t\nlet italic = normal.byAdding {\n\t$0.traitVariants = .italic\n}\n\nlet myGroup = StyleXML(base: normal, [\"bold\": bold, \"italic\": italic])\nlet str = \"Hello \u003cbold\u003eDaniele!\u003c/bold\u003e. You're ready to \u003citalic\u003eplay with us!\u003c/italic\u003e\"\nself.label?.attributedText = str.set(style: myGroup)\n```\n\nThat's the result!\n\n\u003cimg src=\"Documentation_Assests/image_2.png\" alt=\"\" width=400px/\u003e\n\n## Documentation\n\n- [Introduction to `Style`, `StyleXML` \u0026 `StyleRegEx`](#styleStyleXML)\n\t- [String \u0026 Attributed String concatenation](#concatenation)\n\t- [Apply styles to `String` \u0026 `Attributed String`](#manualstyling)\n\t- [Fonts \u0026 Colors in `Style`](#fontscolors)\n\t- [Derivating a `Style`](#derivatingstyle)\n\t- [Support Dynamic Type](#dynamictype)\n\t- [Render XML tagged strings](#customizexmlstrings)\n\t- [Customize XML rendering: react to tag's attributes and unknown tags](#xmlstrings)\n\t- [Custom text transforms](#texttransforms)\n\t- [Local \u0026 Remote Images inside text](#images)\n- [The `StyleManager`](#stylemanager)\n\t- [Register globally available styles](#globalregister)\n\t- [Defer style creation on demand](#defer)\n- [Assign style using Interface Builder](#ib)\n- [All properties of `Style`](#props)\n\nOther info:\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Contributing](#contributing)\n- [Copyright](#copyright)\n\n\u003ca name=\"styleStyleXML\"/\u003e\n\n## Introduction to `Style`, `StyleXML`, `StyleRegEx`\n\nThe main concept behind SwiftRichString is the use of `StyleProtocol` as generic container of the attributes you can apply to both `String` and `NSMutableAttributedString`.\nConcrete classes derivated by `StyleProtocol` are: `Style`, `StyleXML` and `StyleRegEx`.\n\nEach of these classes can be used as source for styles you can apply to a string, substring or attributed string.\n\n\n### `Style`: apply style to strings or attributed strings\n\nA `Style` is a class which encapsulate all the attributes you can apply to a string. The vast majority of the attributes of both AppKit/UIKit are currently available via type-safe properties by this class.\n\nCreating a `Style` instance is pretty simple; using a builder pattern approach the init class require a callback where the self instance is passed and allows you to configure your properties by keeping the code clean and readable:\n\n```swift\nlet style = Style {\n\t$0.font = SystemFonts.Helvetica_Bold.font(size: 20)\n\t$0.color = UIColor.green\n\t// ... set any other attribute\n}\n\nlet attrString = \"Some text\".set(style: style) // attributed string\n```\n\n### `StyleXML`: Apply styles for tag-based complex string\n\n`Style` instances are anonymous; if you want to use a style instance to render a tag-based plain string you need to include it inside a `StyleXML`. You can consider a `StyleXML` as a container of `Styles` (but, in fact, thanks to the conformance to a common `StyleProtocol`'s protocol your group may contains other sub-groups too).\n\n```swift\nlet bodyStyle: Style = ...\nlet h1Style: Style = ...\nlet h2Style: Style = ...\nlet group = StyleXML(base: bodyStyle, [\"h1\": h1Style, \"h2\": h2Style])\n\nlet attrString = \"Some \u003ch1\u003etext\u003c/h1\u003e, \u003ch2\u003ewelcome here\u003c/h2\u003e\".set(style: group)\n```\n\nThe following code defines a group where:\n\n- we have defined a base style. Base style is the style applied to the entire string and can be used to provide a base ground of styles you want to apply to the string.\n- we have defined two other styles named `h1` and `h2`; these styles are applied to the source string when parser encounter some text enclosed by these tags.\n\n\n### `StyleRegEx`: Apply styles via regular expressions\n\n`StyleRegEx` allows you to define a style which is applied when certain regular expression is matched inside the target string/attributed string.\n\n```swift\nlet emailPattern = \"([A-Za-z0-9_\\\\-\\\\.\\\\+])+\\\\@([A-Za-z0-9_\\\\-\\\\.])+\\\\.([A-Za-z]+)\"\nlet style = StyleRegEx(pattern: emailPattern) {\n\t$0.color = UIColor.red\n\t$0.backColor = UIColor.yellow\n}\n\t\t\nlet attrString = \"My email is hello@danielemargutti.com and my website is http://www.danielemargutti.com\".(style: style!)\n```\n\nThe result is this:\n\n\u003cimg src=\"Documentation_Assests/image_4.png\" alt=\"\" width=500px/\u003e\n\n\u003ca name=\"concatenation\"/\u003e\n\n## String \u0026 Attributed String concatenation\nSwiftRichString allows you to simplify string concatenation by providing custom `+` operator between `String`,`AttributedString` (typealias of `NSMutableAttributedString`) and `Style`.\n\nThis a an example:\n\n```swift\nlet body: Style = Style { ... }\nlet big: Style = Style { ... }\nlet attributed: AttributedString = \"hello \".set(style: body)\n\n// the following code produce an attributed string by\n// concatenating an attributed string and two plain string\n// (one styled and another plain).\nlet attStr = attributed + \"\\(username)!\".set(style:big) + \". You are welcome!\"\n```\n\nYou can also use `+` operator to add a style to a plain or attributed string:\n\n```swift\n// This produce an attributed string concatenating a plain\n// string with an attributed string created via + operator\n// between a plain string and a style\nlet attStr = \"Hello\" + (\"\\(username)\" + big)\n```\n\nFinally you can concatente strings using function builders:\n\n```swift\nlet bold = Style { ... }\nlet italic = Style { ... }\n        \nlet attributedString = AttributedString.composing {\n  \"hello\".set(style: bold)\n  \"world\".set(style: italic)\n}\n```\n\n\u003ca name=\"manualstyling\"/\u003e\n\n## Apply styles to `String` \u0026 `Attributed String`\n\nBoth `String` and `Attributed String` (aka `NSMutableAttributedString`) has a come convenience methods you can use to create an manipulate attributed text easily via code:\n\n### Strings Instance Methods\n\n- `set(style: String, range: NSRange? = nil)`: apply a globally registered style to the string (or a substring) by producing an attributed string.\n- `set(styles: [String], range: NSRange? = nil)`: apply an ordered sequence of globally registered styles to the string (or a substring) by producing an attributed string.\n- `set(style: StyleProtocol, range: NSRange? = nil)`: apply an instance of `Style` or `StyleXML` (to render tag-based text) to the string (or a substring) by producting an attributed string.\n- `set(styles: [StyleProtocol], range: NSRange? = nil)`: apply a sequence of `Style`/`StyleXML` instance in order to produce a single attributes collection which will be applied to the string (or substring) to produce an attributed string.\n\nSome examples:\n\n```swift\n// apply a globally registered style named MyStyle to the entire string\nlet a1: AttributedString = \"Hello world\".set(style: \"MyStyle\")\n\n// apply a style group to the entire string\n// commonStyle will be applied to the entire string as base style\n// styleH1 and styleH2 will be applied only for text inside that tags.\nlet styleH1: Style = ...\nlet styleH2: Style = ...\nlet StyleXML = StyleXML(base: commonStyle, [\"h1\" : styleH1, \"h2\" : styleH2])\nlet a2: AttributedString = \"Hello \u003ch1\u003eworld\u003c/h1\u003e, \u003ch2\u003ewelcome here\u003c/h2\u003e\".set(style: StyleXML)\n\n// Apply a style defined via closure to a portion of the string\nlet a3 = \"Hello Guys!\".set(Style({ $0.font = SystemFonts.Helvetica_Bold.font(size: 20) }), range: NSMakeRange(0,4))\n```\n\n### AttributedString Instance Methods\n\nSimilar methods are also available to attributed strings.\n\nThere are three categories of methods:\n\n- `set` methods replace any existing attributes already set on target.\n- `add` add attributes defined by style/styles list to the target\n- `remove` remove attributes defined from the receiver string.\n\nEach of this method alter the receiver instance of the attributed string and also return the same instance in output (so chaining is allowed).\n\n**Add**\n\n- `add(style: String, range: NSRange? = nil)`: add to existing style of string/substring a globally registered style with given name.\n- `add(styles: [String], range: NSRange? = nil)`: add to the existing style of string/substring a style which is the sum of ordered sequences of globally registered styles with given names.\n- `add(style: StyleProtocol, range: NSRange? = nil)`: append passed style instance to string/substring by altering the receiver attributed string.\n- `add(styles: [StyleProtocol], range: NSRange? = nil)`: append passed styles ordered sequence to string/substring by altering the receiver attributed string.\n\n**Set**\n\n- `set(style: String, range: NSRange? = nil)`: replace any existing style inside string/substring with the attributes defined inside the globally registered style with given name.\n- `set(styles: [String], range: NSRange? = nil)`: replace any existing style inside string/substring with the attributes merge of the ordered sequences of globally registered style with given names.\n- `set(style: StyleProtocol, range: NSRange? = nil)`: replace any existing style inside string/substring with the attributes of the passed style instance.\n- `set(styles: [StyleProtocol], range: NSRange? = nil)`: replace any existing style inside string/substring with the attributes of the passed ordered sequence of styles.\n\n**Remove**\n\n- `removeAttributes(_ keys: [NSAttributedStringKey], range: NSRange)`: remove attributes specified by passed keys from string/substring.\n- `remove(_ style: StyleProtocol)`: remove attributes specified by the style from string/substring.\n\nExample:\n\n```swift\nlet a = \"hello\".set(style: styleA)\nlet b = \"world!\".set(style: styleB)\nlet ab = (a + b).add(styles: [coupondStyleA,coupondStyleB]).remove([.foregroundColor,.font])\n```\n\n\u003ca name=\"fontscolors\"/\u003e\n\n## Fonts \u0026 Colors in `Style`\nAll colors and fonts you can set for a `Style` are wrapped by `FontConvertible` and `ColorConvertible` protocols.\n\nSwiftRichString obviously implements these protocols for `UIColor`/`NSColor`, `UIFont`/`NSFont` but also for `String`.\nFor Fonts this mean you can assign a font by providing directly its PostScript name and it will be translated automatically to a valid instance:\n\n```swift\nlet firaLight: UIFont = \"FiraCode-Light\".font(ofSize: 14)\n...\n...\nlet style = Style {\n\t$0.font = \"Jura-Bold\"\n\t$0.size = 24\n\t...\n}\n```\n\nOn UIKit you can also use the `SystemFonts` enum to pick from a type-safe auto-complete list of all available iOS fonts:\n\n```swift\nlet font1 = SystemFonts.Helvetica_Light.font(size: 15)\nlet font2 = SystemFonts.Avenir_Black.font(size: 24)\n```\n\nFor Color this mean you can create valid color instance from HEX strings:\n\n```swift\nlet color: UIColor = \"#0433FF\".color\n...\n...\nlet style = Style {\n\t$0.color = \"#0433FF\"\n\t...\n}\n```\n\nClearly you can still pass instances of both colors/fonts.\n\n\u003ca name=\"derivatingstyle\"/\u003e\n\n## Derivating a `Style`\n\nSometimes you may need to infer properties of a new style from an existing one. In this case you can use `byAdding()` function of `Style` to produce a new style with all the properties of the receiver and the chance to configure additional/replacing attributes.\n\n```swift\nlet initialStyle = Style {\n\t$0.font = SystemFonts.Helvetica_Light.font(size: 15)\n\t$0.alignment = right\n}\n\n// The following style contains all the attributes of initialStyle\n// but also override the alignment and add a different foreground color.\nlet subStyle = bold.byAdding {\n\t$0.alignment = center\n\t$0.color = UIColor.red\n}\n```\n\n\u003ca name=\"dynamictype\"/\u003e\n\n### Conforming to `Dynamic Type`\n\nTo support your fonts/text to dynammically scale based on the users preffered content size, you can implement style's `dynamicText` property. UIFontMetrics properties are wrapped inside `DynamicText` class.\n\n\n```swift\nlet style = Style {\n\t$0.font = UIFont.boldSystemFont(ofSize: 16.0)\n\t$0.dynamicText = DynamicText {\n\t\t$0.style = .body\n\t\t$0.maximumSize = 35.0\n\t\t$0.traitCollection = UITraitCollection(userInterfaceIdiom: .phone)\n    }\n}\n``` \n\n\u003ca name=\"xmlstrings\"/\u003e\n\n## Render XML/HTML tagged strings\n\nSwiftRichString is also able to parse and render xml tagged strings to produce a valid `NSAttributedString` instance. This is particularly useful when you receive dynamic strings from remote services and you need to produce a rendered string easily.\n\nIn order to render an XML string you need to create a compisition of all styles you are planning to render in a single `StyleXML` instance and apply it to your source string as just you made for a single `Style`.\n\nFor example:\n\n```swift\n// The base style is applied to the entire string\nlet baseStyle = Style {\n\t$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize * 1.15)\n\t$0.lineSpacing = 1\n\t$0.kerning = Kerning.adobe(-20)\n}\n\nlet boldStyle = Style {\n\t$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize)\n    $0.dynamicText = DynamicText {\n    $0.style = .body\n    $0.maximumSize = 35.0\n    $0.traitCollection = UITraitCollection(userInterfaceIdiom: .phone)\n    }\n}\n\t\t\nlet italicStyle = Style {\n\t$0.font = UIFont.italicSystemFont(ofSize: self.baseFontSize)\n}\n\n// A group container includes all the style defined.\nlet groupStyle = StyleXML.init(base: baseStyle, [\"b\" : boldStyle, \"i\": italicStyle])\n\n// We can render our string\nlet bodyHTML = \"Hello \u003cb\u003eworld!\u003c/b\u003e, my name is \u003ci\u003eDaniele\u003c/i\u003e\"\nself.textView?.attributedText = bodyHTML.set(style: group)\n```\n\n\u003ca name=\"customizexmlstrings\"/\u003e\n\n## Customize XML rendering: react to tag's attributes and unknown tags\n\nYou can also add custom attributes to your tags and render it as you prefer: you need to provide a croncrete implementation of `XMLDynamicAttributesResolver` protocol and assign it to the `StyleXML`'s `.xmlAttributesResolver` property. \n\nThe protocol will receive two kind of events:\n\n- `applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle)` is received when parser encounter an existing style with custom attributes. Style is applied and event is called so you can make further customizations.\n- `func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String: String]?)` is received when a unknown (not defined in `StyleXML`'s styles) tag is received. You can decide to ignore or perform customizations.\n\nThe following example is used to override text color for when used for any known tag:\n\n```swift\n// First define our own resolver for attributes\nopen class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {\n    \n    public func applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle) {\n        let finalStyleToApply = Style()\n        xmlStyle.enumerateAttributes { key, value  in\n            switch key {\n                case \"color\": // color support\n                    finalStyleToApply.color = Color(hexString: value)\n                \n                default:\n                    break\n            }\n        }\n        \n        attributedString.add(style: finalStyleToApply)\n    }\n}\n\n// Then set it to our's StyleXML instance before rendering text.\nlet groupStyle = StyleXML.init(base: baseStyle, [\"b\" : boldStyle, \"i\": italicStyle])\ngroupStyle.xmlAttributesResolver = MyXMLDynamicAttributesResolver()\n```\n\nThe following example define the behaviour for a non known tag called `rainbow`.  \nSpecifically it alter the string by setting a custom color for each letter of the source string.\n\n```swift\nopen class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {\n\n  public override func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String : String]?) {\n        super.styleForUnknownXMLTag(tag, to: \u0026attributedString, attributes: attributes)\n        \n        if tag == \"rainbow\" {\n            let colors = UIColor.randomColors(attributedString.length)\n            for i in 0..\u003cattributedString.length {\n                attributedString.add(style: Style({\n                    $0.color = colors[i]\n                }), range: NSMakeRange(i, 1))\n            }\n        }\n        \n    }\n  }\n}\n```\nYou will receive all read tag attributes inside the `attributes` parameter.  \nYou can alter attributes or the entire string received as `inout` parameter in `attributedString` property.\n\nA default resolver is also provided by the library and used by default: `StandardXMLAttributesResolver`.  It will support both `color` attribute in tags and `\u003ca href\u003e` tag with url linking.\n\n```swift\nlet sourceHTML = \"My \u003cb color=\\\"#db13f2\\\"\u003ewebpage\u003c/b\u003e is really \u003cb\u003ecool\u003c/b\u003e. Take a look \u003ca href=\\\"http://danielemargutti.com\\\"\u003ehere\u003c/a\u003e\"\n        \nlet styleBase = Style({\n    $0.font = UIFont.boldSystemFont(ofSize: 15)\n})\n        \nlet styleBold = Style({\n    $0.font = UIFont.boldSystemFont(ofSize: 20)\n    $0.color = UIColor.blue\n})\n        \nlet groupStyle = StyleXML.init(base: styleBase, [\"b\" : styleBold])\nself.textView?.attributedText = sourceHTML.set(style: groupStyle)\n```\n\nThe result is this:\n\n\u003cimg src=\"Documentation_Assests/image_5.png\" alt=\"\" width=500px/\u003e\n\nwhere the `b` tag's blue color was overriden by the color tag attributes and the link in 'here' is clickable.\n\n\u003ca name=\"texttransforms\"/\u003e\n\n## Custom Text Transforms\n\nSometimes you want to apply custom text transforms to your string; for example you may want to make some text with a given style uppercased with current locale.  \nIn order to provide custom text transform in `Style` instances just set one or more `TextTransform` to your `Style`'s `.textTransforms` property:\n\n```swift\nlet allRedAndUppercaseStyle = Style({\n\t$0.font = UIFont.boldSystemFont(ofSize: 16.0)\n\t$0.color = UIColor.red\n\t$0.textTransforms = [\n\t\t.uppercaseWithLocale(Locale.current)\n\t]\n})\n\nlet text = \"test\".set(style: allRedAndUppercaseStyle) // will become red and uppercased (TEST)\n```\n\nWhile `TextTransform` is an enum with a predefined set of transform you can also provide your own function which have a `String` as source and another `String` as destination:\n\n```swift\nlet markdownBold = Style({\n\t$0.font = UIFont.boldSystemFont(ofSize: 16.0)\n\t$0.color = UIColor.red\n\t$0.textTransforms = [\n\t\t.custom({\n\t\t\treturn \"**\\($0)**\"\n\t\t})\n\t]\n})\n```\n\nAll text transforms are applied in the same ordered you set in `textTransform` property.\n\n\u003ca name=\"images\"/\u003e\n\n## Local \u0026 Remote Images inside text\n\nSwiftRichString supports local and remote attached images along with attributed text.  \nYou can create an attributed string with an image with a single line:\n\n```swift\n// You can specify the bounds of the image, both for size and the location respecting the base line of the text.\nlet localTextAndImage = AttributedString(image: UIImage(named: \"rocket\")!, bounds: CGRect(x: 0, y: -20, width: 25, height: 25))\n\n// You can also load a remote image. If you not specify bounds size is the original size of the image.\nlet remoteTextAndImage = AttributedString(imageURL: \"http://...\")\n\n// You can now compose it with other attributed or simple string\nlet finalString = \"...\".set(style: myStyle) + remoteTextAndImage + \" some other text\"\n```\n\nImages can also be loaded by rending an XML string by using the `img` tag (with `named` tag for local resource and `url` for remote url).  \n`rect` parameter is optional and allows you to specify resize and relocation of the resource.\n\n```swift\nlet taggedText = \"\"\"\n  Some text and this image:\n  \u003cimg named=\"rocket\" rect=\"0,-50,30,30\"/\u003e\n  \n  This other is loaded from remote URL:\n  \u003cimg url=\"https://www.macitynet.it/wp-content/uploads/2018/05/video_ApplePark_magg18.jpg\"/\u003e\n\"\"\"\n\nself.textView?.attributedText = taggedText.set(style: ...)\n```\n\nThis is the result:\n\n\u003cimg src=\"Documentation_Assests/image_6.png\" alt=\"\" width=100px/\u003e\n\nSometimes you may want to provide these images lazily. In order to do it just provide a custom implementation of the `imageProvider` callback in `StyleXML` instance:\n\n```swift\nlet xmlText = \"- \u003cimg named=\\\"check\\\" background=\\\"#0000\\\"/\u003e has done!\"\n        \nlet xmlStyle = StyleXML(base: {\n  /// some attributes for base style\n})\n\n// This method is called when a new `img` tag is found. It's your chance to\n// return a custom image. If you return `nil` (or you don't implement this method)\n// image is searched inside any bundled `xcasset` file.\nxmlStyle.imageProvider = { (imageName, attributes) in\n\tswitch imageName {\n\t\tcase \"check\":\n\t\t   // create \u0026 return your own image\n\t\tdefault:\n\t\t   // ...\n\t}\n}\n        \nself.textView?.attributedText = xmlText.set(style: x)\n```\n\n\u003ca name=\"stylemanager\"/\u003e\n\n## The `StyleManager`\n\n\u003ca name=\"globalregister\"/\u003e\n\n## Register globally available styles\nStyles can be created as you need or registered globally to be used once you need.\nThis second approach is strongly suggested because allows you to theme your app as you need and also avoid duplication of the code.\n\nTo register a `Style` or a `StyleXML` globally you need to assign an unique identifier to it and call `register()` function via `Styles` shortcut (which is equal to call `StylesManager.shared`).\n\nIn order to keep your code type-safer you can use a non-instantiable struct to keep the name of your styles, then use it to register style:\n\n```swift\n// Define a struct with your styles names\npublic struct StyleNames {\n\tpublic static let body: String = \"body\"\n\tpublic static let h1: String = \"h1\"\n\tpublic static let h2: String = \"h2\"\n\t\n\tprivate init { }\n}\n```\n\nThen you can:\n\n```swift\nlet bodyStyle: Style = ...\nStyles.register(StyleNames.body, bodyStyle)\n```\n\nNow you can use it everywhere inside the app; you can apply it to a text just using its name:\n\n```swift\nlet text = \"hello world\".set(StyleNames.body)\n```\n\nor you can assign `body` string to the `styledText` via Interface Builder designable property.\n\n\u003ca name=\"defer\"/\u003e\n\n## Defer style creation on demand\nSometimes you may need to return a particular style used only in small portion of your app; while you can still set it directly you can also defer its creation in `StylesManager`.\n\nBy implementing `onDeferStyle()` callback you have an option to create a new style once required: you will receive the identifier of the style.\n\n```swift\nStyles.onDeferStyle = { name in\n\t\t\t\n\tif name == \"MyStyle\" {\n\t\tlet normal = Style {\n\t\t\t$0.font = SystemFonts.Helvetica_Light.font(size: 15)\n\t\t}\n\t\t\t\t\n\t\tlet bold = Style {\n\t\t\t$0.font = SystemFonts.Helvetica_Bold.font(size: 20)\n\t\t\t$0.color = UIColor.red\n\t\t\t$0.backColor = UIColor.yellow\n\t\t}\n\t\t\t\t\n\t\tlet italic = normal.byAdding {\n\t\t\t$0.traitVariants = .italic\n\t\t}\n\t\t\t\t\n\t\treturn (StyleXML(base: normal, [\"bold\": bold, \"italic\": italic]), true)\n\t}\n\t\t\t\n\treturn (nil,false)\n}\n```\nThe following code return a valid style for `myStyle` identifier and cache it; if you don't want to cache it just return `false` along with style instance.\n\nNow you can use your style to render, for example, a tag based text into an `UILabel`: just set the name of the style to use.\n\n\u003cimg src=\"Documentation_Assests/image_3.png\" alt=\"\" width=400px\u003e\n\n\u003ca name=\"ib\"/\u003e\n\n## Assign style using Interface Builder\nSwiftRichString can be used also via Interface Builder.\n\n- `UILabel`\n- `UITextView`\n- `UITextField`\n\nhas three additional properties:\n\n- `styleName: String` (available via IB): you can set it to render the text already set via Interface Builder with a style registered globally before the parent view of the UI control is loaded.\n- `style: StyleProtocol`: you can set it to render the text of the control with an instance of style instance.\n- `styledText: String`: use this property, instead of `attributedText` to set a new text for the control and render it with already set style. You can continue to use `attributedText` and set the value using `.set()` functions of `String`/`AttributedString`.\n\nAssigned style can be a `Style`, `StyleXML` or `StyleRegEx`:\n\n- if style is a `Style` the entire text of the control is set with the attributes defined by the style.\n- if style is a `StyleXML` a base attribute is set (if `base` is valid) and other attributes are applied once each tag is found.\n- if style is a `StyleRegEx` a base attribute is set (if `base` is valid) and the attribute is applied only for matches of the specified pattern.\n\nTypically you will set the style of a label via `Style Name` (`styleName`) property in IB and update the content of the control by setting the `styledText`:\n\n```swift\n// use `styleName` set value to update a text with the style\nself.label?.styledText = \"Another text to render\" // text is rendered using specified `styleName` value.\n```\n\nOtherwise you can set values manually:\n\n```swift\n// manually set the an attributed string\nself.label?.attributedText = (self.label?.text ?? \"\").set(myStyle)\n\n// manually set the style via instance\nself.label?.style = myStyle\nself.label?.styledText = \"Updated text\"\n```\n\n\u003ca name=\"props\"/\u003e\n\n## Properties available via `Style` class\nThe following properties are available:\n\n| PROPERTY                      | TYPE                                  | DESCRIPTION                                                                                                                                | \n|-------------------------------|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| \n| size                          | `CGFloat`                               | font size in points                                                                                                                        | \n| font                          | `FontConvertible`                       | font used in text                                                                                                                          | \n| color                         | `ColorConvertible`                      | foreground color of the text                                                                                                               | \n| backColor                     | `ColorConvertible`                      | background color of the text                                                                                                               | \n| shadow                     | `NSShadow`                      | shadow effect of the text                                                                                                             | \n| underline                     | `(NSUnderlineStyle?,ColorConvertible?)` | underline style and color (if color is nil foreground is used)                                                                             | \n| strikethrough                 | `(NSUnderlineStyle?,ColorConvertible?)` | strikethrough style and color (if color is nil foreground is used)                                                                         | \n| baselineOffset                | `Float`                                 | character’s offset from the baseline, in point                                                                                             | \n| paragraph                     | `NSMutableParagraphStyle`               | paragraph attributes                                                                                                                       | \n| lineSpacing                   | `CGFloat`                               | distance in points between the bottom of one line fragment and the top of the next                                                         | \n| paragraphSpacingBefore        | `CGFloat`                               | distance between the paragraph’s top and the beginning of its text content                                                                 | \n| paragraphSpacingAfter         | `CGFloat`                               | space (measured in points) added at the end of the paragraph                                                                               | \n| alignment                     | `NSTextAlignment`                       | text alignment of the receiver                                                                                                             | \n| firstLineHeadIndent           | `CGFloat`                               | distance (in points) from the leading margin of a text container to the beginning of the paragraph’s first line.                           | \n| headIndent                    | `CGFloat`                               | The distance (in points) from the leading margin of a text container to the beginning of lines other than the first.                       | \n| tailIndent                    | `CGFloat`                               | this value is the distance from the leading margin, If 0 or negative, it’s the distance from the trailing margin.                          | \n| lineBreakMode                 | `LineBreak`                             | mode that should be used to break lines                                                                                                    | \n| minimumLineHeight             | `CGFloat`                               | minimum height in points that any line in the receiver will occupy regardless of the font size or size of any attached graphic             | \n| maximumLineHeight             | `CGFloat`                               | maximum height in points that any line in the receiver will occupy regardless of the font size or size of any attached graphic             | \n| baseWritingDirection          | `NSWritingDirection`                    | initial writing direction used to determine the actual writing direction for text                                                          | \n| lineHeightMultiple            | `CGFloat`                               | natural line height of the receiver is multiplied by this factor (if positive) before being constrained by minimum and maximum line height | \n| hyphenationFactor             | `Float`                                 | threshold controlling when hyphenation is attempted                                                                                        | \n| ligatures                     | `Ligatures`                             | Ligatures cause specific character combinations to be rendered using a single custom glyph that corresponds to those characters            | \n| speaksPunctuation             | `Bool`                                  | Enable spoken of all punctuation in the text                                                                                               | \n| speakingLanguage              | `String`                                | The language to use when speaking a string (value is a BCP 47 language code string).                                                       | \n| speakingPitch                 | `Double`                                | Pitch to apply to spoken content                                                                                                           | \n| speakingPronunciation         | `String`                                |                                                                                                                                            | \n| shouldQueueSpeechAnnouncement | `Bool`                                  | Spoken text is queued behind, or interrupts, existing spoken content                                                                       | \n| headingLevel                  | `HeadingLevel`                          | Specify the heading level of the text                                                                                                      | \n| numberCase                    | `NumberCase`                            | \"Configuration for the number case, also known as \"\"figure style\"\"\"                                                                        | \n| numberSpacing                 | `NumberSpacing`                         | \"Configuration for number spacing, also known as \"\"figure spacing\"\"\"                                                                       | \n| fractions                     | `Fractions`                             | Configuration for displyaing a fraction                                                                                                    | \n| superscript                   | `Bool`                                  | Superscript (superior) glpyh variants are used, as in footnotes_.                                                                          | \n| `subscript`                   | `Bool`                                  | Subscript (inferior) glyph variants are used: v_.                                                                                          | \n| ordinals                      | `Bool`                                  | Ordinal glyph variants are used, as in the common typesetting of 4th.                                                                      | \n| scientificInferiors           | `Bool`                                  | Scientific inferior glyph variants are used: H_O                                                                                           | \n| smallCaps                     | `Set\u003cSmallCaps\u003e`                       | Configure small caps behavior.                                                                                                             | \n| stylisticAlternates           | `StylisticAlternates`                   | Different stylistic alternates available for customizing a font.                                                                           | \n| contextualAlternates          | `ContextualAlternates`                  | Different contextual alternates available for customizing a font.                                                                          | \n| kerning                       | `Kerning`                               | Tracking to apply.                                                                                                                         | \n| traitVariants                 | `TraitVariant`                          | Describe trait variants to apply to the font                                                                                               | \n\n\u003ca name=\"requirements\"/\u003e\n\n## Requirements\n\n* Swift 5.1+\n* iOS 8.0+\n* macOS 11.0+\n* watchOS 2.0+\n* tvOS 11.0+\n\n\u003ca name=\"installation\"/\u003e\n\n## Installation\n\n### CocoaPods\n\n[CocoaPods](https://cocoapods.org/) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your Podfile:\n\n```ruby\npod 'SwiftRichString'\n```\n\n### Swift Package Manager\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but Alamofire does support its use on supported platforms.\n\nOnce you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the dependencies value of your Package.swift.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/malcommac/SwiftRichString.git\", from: \"3.5.0\")\n]\n```\n\n### Carthage\n\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.  \nTo integrate SwiftRichString into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"malcommac/SwiftRichString\"\n```\n\nRun `carthage` to build the framework and drag the built `SwiftRichString.framework` into your Xcode project.\n\n\u003ca name=\"contributing\" /\u003e\n\n## Contributing\n\nIssues and pull requests are welcome!\nContributors are expected to abide by the [Contributor Covenant Code of Conduct](https://github.com/malcommac/SwiftRichString/blob/master/CONTRIBUTING.md).\n\n## Copyright\n\nSwiftRichString is available under the MIT license. See the LICENSE file for more info.\n\nDaniele Margutti: [hello@danielemargutti.com](mailto:hello@danielemargutti.com), [@danielemargutti](https://twitter.com/danielemargutti)\n","funding_links":["https://github.com/sponsors/malcommac","https://www.paypal.com/paypalme2/danielemargutti"],"categories":["Libs","UI","Text","UI Components","HarmonyOS","Swift","Text [🔝](#readme)","xml-parsing"],"sub_categories":["Text","Layout","Other free courses","Other Testing","Keychain","Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalcommac%2FSwiftRichString","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalcommac%2FSwiftRichString","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalcommac%2FSwiftRichString/lists"}