Skip to content

Commit

Permalink
Add tvOS support
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Pospesel authored and mpospese committed Sep 28, 2022
1 parent b3f1017 commit 3424e5a
Show file tree
Hide file tree
Showing 23 changed files with 191 additions and 109 deletions.
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ let package = Package(
name: "YMatterType",
defaultLocalization: "en",
platforms: [
.iOS(.v14)
.iOS(.v14),
.tvOS(.v14)
],
products: [
.library(
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![Y-Matter Type](https://mpospese.com/wp-content/uploads/2022/08/YMatterType-hero-compact.jpeg)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyml-org%2FYMatterType%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/yml-org/YMatterType) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyml-org%2FYMatterType%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/yml-org/YMatterType)
_An opinionated take on Design System Typography for iOS._
_An opinionated take on Design System Typography for iOS and tvOS._

This framework uses Figma's concept of Typography to create text-based UI elements (labels, buttons, text fields, and text views) that render themselves as described in Figma design files (especially sizing themselves according to line height) while also supporting Dynamic Type scaling and the Bold Text accessibility setting.

Expand All @@ -17,7 +17,7 @@ Documentation is automatically generated from source code comments and rendered

## What is Y—MatterType?

Y—MatterType is a framework that assists in getting typography done right when constructing iOS user interfaces from Figma-based designs.
Y—MatterType is a framework that assists in getting typography done right when constructing iOS and tvOS user interfaces from Figma-based designs.

Y—MatterType aims to achieve the following goals:

Expand Down
24 changes: 12 additions & 12 deletions Sources/YMatterType/Elements/TypographyButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import UIKit
open class TypographyButton: UIButton {
/// The current typographical layout
public private(set) var layout: TypographyLayout!

/// Typography to be used for this buttons's title label
public var typography: Typography {
didSet {
adjustFonts()
}
}

/// (Optional) maximum point size when scaling the font.
///
/// Value should be greater than Typography.fontSize.
Expand Down Expand Up @@ -61,15 +61,15 @@ open class TypographyButton: UIButton {
super.init(frame: .zero)
build()
}

/// :nodoc:
required public init?(coder: NSCoder) { nil }

private enum TextSetMode {
case text
case attributedText
}

private var textSetMode: TextSetMode = .text

/// :nodoc:
Expand All @@ -79,15 +79,15 @@ open class TypographyButton: UIButton {
textSetMode = .text
styleText(title, for: state)
}

/// :nodoc:
override public func setAttributedTitle(_ title: NSAttributedString?, for state: UIControl.State) {
// When text is set, we may need to re-style it as attributedText
// with the correct paragraph style to achieve the desired line height.
textSetMode = .attributedText
styleAttributedText(title, for: state)
}

/// Gets or sets the text alignment of the button's title label.
/// Default value = `.natural`
public var textAlignment: NSTextAlignment = .natural {
Expand All @@ -99,7 +99,7 @@ open class TypographyButton: UIButton {
}
}
}

/// Gets or sets the line break mode of the button's title label.
/// Default value = `.byTruncatingTail`
public var lineBreakMode: NSLineBreakMode = .byTruncatingTail {
Expand All @@ -119,7 +119,7 @@ open class TypographyButton: UIButton {
if traitCollection.hasDifferentFontAppearance(comparedTo: previousTraitCollection) {
adjustFonts()
}

if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
adjustColors()
}
Expand Down Expand Up @@ -212,16 +212,16 @@ private extension TypographyButton {
adjustColors()
adjustBreakpoint()
}

func configure() {
setTitleColor(.label, for: .normal)
titleLabel?.adjustsFontForContentSizeCategory = true
}

@objc func contentSizeDidChange() {
adjustFonts()
}

func restyleText() {
styleAttributedText(currentAttributedTitle, for: state)
}
Expand All @@ -240,7 +240,7 @@ private extension TypographyButton {
let attributedText = layout.styleText(newValue, lineMode: lineMode)
super.setAttributedTitle(attributedText, for: state)
}

func styleAttributedText(_ newValue: NSAttributedString?, for state: UIControl.State) {
defer { invalidateIntrinsicContentSize() }
guard let layout = layout,
Expand Down
22 changes: 11 additions & 11 deletions Sources/YMatterType/Elements/TypographyLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ open class TypographyLabel: UILabel {
adjustFonts()
}
}

/// (Optional) maximum point size when scaling the font.
///
/// Value should be greater than Typography.fontSize.
Expand Down Expand Up @@ -61,15 +61,15 @@ open class TypographyLabel: UILabel {
super.init(frame: .zero)
build()
}

/// :nodoc:
required public init?(coder: NSCoder) { nil }

private enum TextSetMode {
case text
case attributedText
}

private var textSetMode: TextSetMode = .text

/// :nodoc:
Expand All @@ -82,7 +82,7 @@ open class TypographyLabel: UILabel {
styleText(newValue)
}
}

/// :nodoc:
override public var attributedText: NSAttributedString? {
get { super.attributedText }
Expand All @@ -104,7 +104,7 @@ open class TypographyLabel: UILabel {
}
}
}

/// :nodoc:
override public var lineBreakMode: NSLineBreakMode {
didSet {
Expand All @@ -123,7 +123,7 @@ open class TypographyLabel: UILabel {
if traitCollection.hasDifferentFontAppearance(comparedTo: previousTraitCollection) {
adjustFonts()
}

if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
adjustColors()
}
Expand All @@ -132,7 +132,7 @@ open class TypographyLabel: UILabel {
adjustBreakpoint()
}
}

/// Call this if you've made a change that would require text to be re-styled. (Normally this is not necessary).
/// Override this if you need to do something additional when preferred content size
/// or legibility weight has changed
Expand All @@ -145,7 +145,7 @@ open class TypographyLabel: UILabel {
font = layout.font
restyleText()
}

/// Override this if you have colors that will not automatically adjust to
/// Light / Dark mode, etc. This can be the case for CGColor or
/// non-template images (or backgroundImages).
Expand All @@ -167,11 +167,11 @@ private extension TypographyLabel {
adjustColors()
adjustBreakpoint()
}

func configure() {
adjustsFontForContentSizeCategory = true
}

func restyleText() {
if textSetMode == .text {
styleText(text)
Expand All @@ -193,7 +193,7 @@ private extension TypographyLabel {
// Set attributed text to match typography
super.attributedText = layout.styleText(newValue, lineMode: lineMode)
}

func styleAttributedText(_ newValue: NSAttributedString?) {
defer { invalidateIntrinsicContentSize() }
guard let layout = layout,
Expand Down
21 changes: 19 additions & 2 deletions Sources/YMatterType/Elements/TypographyTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,17 @@ open class TypographyTextField: UITextField {
}
}

/// Insets to apply around the functional area of the `UITextField`. Defaults to `.zero`
public var textInsets: UIEdgeInsets = .zero {
/// Default text insets (values vary by platform)
public static var defaultTextInsets: UIEdgeInsets = {
#if os(tvOS)
UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
#else
.zero
#endif
}()

/// Insets to apply around the functional area of the `UITextField`.
public var textInsets: UIEdgeInsets = TypographyTextField.defaultTextInsets {
didSet {
if textInsets != oldValue {
invalidateIntrinsicContentSize()
Expand Down Expand Up @@ -162,12 +171,20 @@ open class TypographyTextField: UITextField {

/// :nodoc
open override func textRect(forBounds bounds: CGRect) -> CGRect {
#if os(tvOS)
bounds.inset(by: textInsets)
#else
super.textRect(forBounds: bounds).inset(by: textInsets)
#endif
}

/// :nodoc
open override func editingRect(forBounds bounds: CGRect) -> CGRect {
#if os(tvOS)
bounds.inset(by: textInsets)
#else
super.editingRect(forBounds: bounds).inset(by: textInsets)
#endif
}

/// :nodoc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extension NSParagraphStyle {
paragraphStyle.lineSpacing = lineSpacing
return paragraphStyle
}

/// Combines line height multiple with the existing style
/// - Parameter lineHeightMultiple: the line height multiple to use
/// - Returns: Current paragraph style combined with line height multiple
Expand All @@ -26,7 +26,7 @@ extension NSParagraphStyle {
paragraphStyle.lineHeightMultiple = lineHeightMultiple
return paragraphStyle
}

/// Combines text alignment with the existing style
/// - Parameter alignment: the text alignment to use
/// - Returns: Current paragraph style combined with text alignment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import UIKit
public struct DefaultFontFamily: FontFamily {
/// Suffix to use for italic family font names "Italic"
public static let italicSuffix = "Italic"

/// Font family root name, e.g. "AvenirNext"
public let familyName: String

/// Font style, e.g. regular or italic
public let style: Typography.FontStyle

/// Initialize a `DefaultFontFamily` object
/// - Parameters:
/// - familyName: font family name
Expand All @@ -27,7 +27,7 @@ public struct DefaultFontFamily: FontFamily {
self.familyName = familyName
self.style = style
}

/// Optional suffix to use for the font name.
///
/// Used by `FontFamily.fontName(for:compatibleWith:)`
Expand Down
16 changes: 8 additions & 8 deletions Sources/YMatterType/Typography/FontFamily/FontFamily.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import os
public protocol FontFamily {
/// Font family root name, e.g. "AvenirNext"
var familyName: String { get }

/// Optional suffix to use for the font name.
///
/// Used by `FontFamily.fontName(for:compatibleWith:)`
Expand All @@ -31,7 +31,7 @@ public protocol FontFamily {

// The following four methods have default implementations that
// can be overridden in custom implementations of `FontFamily`.

/// Returns a font for the specified `weight` and `pointSize` that is compatible with the `traitCollection`
/// - Parameters:
/// - weight: desired font weight
Expand All @@ -50,12 +50,12 @@ public protocol FontFamily {
/// If `nil` then `UIAccessibility.isBoldTextEnabled` will be considered instead
/// - Returns: The font name formulated from `familyName` and `weight`
func fontName(for weight: Typography.FontWeight, compatibleWith traitCollection: UITraitCollection?) -> String

/// Generates a weight name suffix as part of a full font name. Not all fonts support all 9 weights.
/// - Parameter weight: desired font weight
/// - Returns: The weight name to use
func weightName(for weight: Typography.FontWeight) -> String

/// Returns the alternate weight to use if user has requested a bold font. e.g. might convert `.regular`
/// to `.semibold`. Not all fonts support all 9 weights.
/// - Parameter weight: desired font weight
Expand Down Expand Up @@ -94,7 +94,7 @@ extension FontFamily {
}
return font
}

public func fontName(
for weight: Typography.FontWeight,
compatibleWith traitCollection: UITraitCollection?
Expand All @@ -105,7 +105,7 @@ extension FontFamily {
let weightName = weightName(for: actualWeight)
return "\(familyName)-\(weightName)\(fontNameSuffix)"
}

public func weightName(for weight: Typography.FontWeight) -> String {
// Default font name suffix by weight
switch weight {
Expand All @@ -129,7 +129,7 @@ extension FontFamily {
return "Black"
}
}

public func accessibilityBoldWeight(for weight: Typography.FontWeight) -> Typography.FontWeight {
// By default returns the next heavier supported weight (if any), otherwise the heaviest supported weight
let weights = supportedWeights.sorted(by: { $0.rawValue < $1.rawValue })
Expand All @@ -147,7 +147,7 @@ extension FontFamily {
guard let traitCollection = traitCollection else {
return UIAccessibility.isBoldTextEnabled
}

return traitCollection.legibilityWeight == .bold
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public struct SystemFontFamily: FontFamily {
// The system font has a private font family name (literally ".SFUI"), so
// just return empty string for familyName. The system font can't be retrieved by name anyway.
public var familyName: String { "" }

/// Returns a font for the specified `weight` and `pointSize` that is compatible with the `traitCollection`
/// - Parameters:
/// - weight: desired font weight
Expand Down

0 comments on commit 3424e5a

Please sign in to comment.