Created
May 13, 2021 19:42
-
-
Save mmdock/0167f09c2f8191e0b18ae7bb49991e12 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public struct TextStyle: Equatable { | |
// MARK: - Instance Properties | |
public let font: UIFont? | |
public let color: UIColor? | |
public let backgroundColor: UIColor? | |
public let strikethrough: Bool | |
public let underline: Bool | |
public let paragraphSpacing: CGFloat? | |
public let paragraphIndent: CGFloat? | |
public let lineHeight: CGFloat? | |
public let letterSpacing: CGFloat? | |
public let lineBreakMode: NSLineBreakMode? | |
public let alignment: NSTextAlignment? | |
public let link: URL? | |
// MARK: - Initializers | |
public init( | |
font: UIFont? = nil, | |
color: UIColor? = nil, | |
backgroundColor: UIColor? = nil, | |
strikethrough: Bool = false, | |
underline: Bool = false, | |
paragraphSpacing: CGFloat? = nil, | |
paragraphIndent: CGFloat? = nil, | |
lineHeight: CGFloat? = nil, | |
letterSpacing: CGFloat? = nil, | |
lineBreakMode: NSLineBreakMode? = nil, | |
alignment: NSTextAlignment? = nil, | |
link: URL? = nil | |
) { | |
self.font = font | |
self.color = color | |
self.backgroundColor = backgroundColor | |
self.strikethrough = strikethrough | |
self.underline = underline | |
self.paragraphSpacing = paragraphSpacing | |
self.paragraphIndent = paragraphIndent | |
self.lineHeight = lineHeight | |
self.letterSpacing = letterSpacing | |
self.lineBreakMode = lineBreakMode | |
self.alignment = alignment | |
self.link = link | |
} | |
// MARK: - Instance Methods | |
private func attributes(paragraphStyle: NSParagraphStyle?) -> [NSAttributedString.Key: Any] { | |
var attributes: [NSAttributedString.Key: Any] = [:] | |
if let paragraphStyle = paragraphStyle { | |
attributes[.paragraphStyle] = paragraphStyle | |
} | |
if let font = font { | |
attributes[.font] = font | |
} | |
if let color = color { | |
attributes[.foregroundColor] = color | |
} | |
if let backgroundColor = backgroundColor { | |
attributes[.backgroundColor] = backgroundColor | |
} | |
if strikethrough { | |
attributes[.strikethroughStyle] = NSUnderlineStyle.single.rawValue | |
} | |
if underline { | |
attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue | |
} | |
if let letterSpacing = letterSpacing { | |
attributes[.kern] = letterSpacing | |
} | |
if let link = link { | |
attributes[.link] = link | |
} | |
return attributes | |
} | |
// MARK: - | |
public func paragraphStyle() -> NSParagraphStyle { | |
let paragraphStyle = NSMutableParagraphStyle() | |
if let lineHeight = lineHeight { | |
paragraphStyle.minimumLineHeight = lineHeight | |
paragraphStyle.maximumLineHeight = lineHeight | |
} | |
if let paragraphSpacing = paragraphSpacing { | |
paragraphStyle.paragraphSpacing = paragraphSpacing | |
} | |
if let paragraphIndent = paragraphIndent { | |
paragraphStyle.firstLineHeadIndent = paragraphIndent | |
} | |
if let lineBreakMode = lineBreakMode { | |
paragraphStyle.lineBreakMode = lineBreakMode | |
} | |
if let alignment = alignment { | |
paragraphStyle.alignment = alignment | |
} | |
return paragraphStyle | |
} | |
public func attributes(includingParagraphStyle: Bool = true) -> [NSAttributedString.Key: Any] { | |
if includingParagraphStyle { | |
return attributes(paragraphStyle: paragraphStyle()) | |
} else { | |
return attributes(paragraphStyle: nil) | |
} | |
} | |
public func attributedString( | |
_ string: String, | |
includingParagraphStyle: Bool = true | |
) -> NSAttributedString { | |
return NSAttributedString(string: string, style: self, includingParagraphStyle: includingParagraphStyle) | |
} | |
public func mutableString( | |
_ string: String, | |
includingParagraphStyle: Bool = true | |
) -> NSMutableAttributedString { | |
return NSMutableAttributedString(string: string, style: self, includingParagraphStyle: includingParagraphStyle) | |
} | |
// MARK: - | |
public func withFont(_ font: UIFont?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withColor(_ color: UIColor?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withBackgroundColor(_ backgroundColor: UIColor?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withStrikethrough(_ strikethrough: Bool) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withUnderline(_ underline: Bool) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withParagraphSpacing(_ paragraphSpacing: CGFloat?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withParagraphIndent(_ paragraphIndent: CGFloat?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withLineHeight(_ lineHeight: CGFloat?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withLetterSpacing(_ letterSpacing: CGFloat?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withLineBreakMode(_ lineBreakMode: NSLineBreakMode?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withAlignment(_ alignment: NSTextAlignment?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withLink(_ link: URL?) -> TextStyle { | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
public func withLink(_ stringLink: String) -> TextStyle { | |
var link: URL? | |
if let url = URL(string: stringLink ) { | |
link = url | |
} | |
return TextStyle( | |
font: font, | |
color: color, | |
backgroundColor: backgroundColor, | |
strikethrough: strikethrough, | |
underline: underline, | |
paragraphSpacing: paragraphSpacing, | |
paragraphIndent: paragraphIndent, | |
lineHeight: lineHeight, | |
letterSpacing: letterSpacing, | |
lineBreakMode: lineBreakMode, | |
alignment: alignment, | |
link: link | |
) | |
} | |
} | |
public extension NSAttributedString { | |
// MARK: - Initializers | |
convenience init(string: String, style: TextStyle, includingParagraphStyle: Bool = true) { | |
self.init(string: string, attributes: style.attributes(includingParagraphStyle: includingParagraphStyle)) | |
} | |
} | |
public extension NSMutableAttributedString { | |
@discardableResult | |
func withSubstringStyle(substring: String, style: TextStyle, includingParagraphStyle: Bool = false) -> NSMutableAttributedString { | |
let range = self.mutableString.range(of: substring) | |
self.setAttributes(style.attributes(includingParagraphStyle: includingParagraphStyle), range: range) | |
return self | |
} | |
func append(_ substring: String, withStyle style: TextStyle, includingParagraphStyle: Bool = false) { | |
self.append(NSMutableAttributedString(string: substring, attributes: style.attributes(includingParagraphStyle: includingParagraphStyle))) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment