Skip to content

zijievv/sf-symbols-generator

Repository files navigation

SF Symbols Generator

A Swift macro generating type-safe SF Symbols

Declaration

@freestanding(declaration, names: named(SFSymbol))
public macro SFSymbol(
    accessLevel: AccessLevel = .internal,
    @SFSymbolNamesBuilder namesBuilder: () -> [String])

@freestanding(declaration, names: named(SFSymbol)) 
public macro SFSymbol(accessLevel: AccessLevel = .internal, names: [String])

Usage

Source code:

import SFSymbolsGenerator
import SwiftUI

#SFSymbol {
    "star"
    "case"
    "star.square.on.square"
}

extension Image {
    init(symbol: SFSymbol) {
        self.init(systemName: symbol.name)
    }
}

let starImage = Image(symbol: .star)
// UIKit
let caseImage: UIImage = SFSymbol.case.uiImage()
// AppKit
let img: NSImage = SFSymbol.starSquareOnSquare.nsImage(accessibilityDescription: "")

Expanded source:

enum SFSymbol: String {
    case star
    case `case`
    case starSquareOnSquare = "star.square.on.square"

    var name: String {
        self.rawValue
    }

    @available(iOS 13.0, *)
    @available(macCatalyst 13.0, *)
    @available(macOS 11.0, *)
    @available(tvOS 13.0, *)
    @available(watchOS 6.0, *)
    func image() -> Image {
        Image(systemName: self.rawValue)
    }

    @available(iOS 16.0, *)
    @available(macCatalyst 16.0, *)
    @available(macOS 13.0, *)
    @available(tvOS 16.0, *)
    @available(watchOS 9.0, *)
    func image(variableValue: Double?) -> Image {
        Image(systemName: self.rawValue, variableValue: variableValue)
    }

    #if canImport (UIKit)
    @available(iOS 13.0, *)
    @available(macCatalyst 13.0, *)
    @available(tvOS 13.0, *)
    @available(watchOS 6.0, *)
    func uiImage() -> UIImage {
        UIImage(systemName: self.rawValue)!
    }

    @available(iOS 13.0, *)
    @available(macCatalyst 13.1, *)
    @available(tvOS 13.0, *)
    @available(watchOS 6.0, *)
    func uiImage(withConfiguration configuration: UIImage.Configuration?) -> UIImage {
        UIImage(systemName: self.rawValue, withConfiguration: configuration)!
    }

    @available(iOS 16.0, *)
    @available(macCatalyst 16.0, *)
    @available(tvOS 16.0, *)
    @available(watchOS 9.0, *)
    func uiImage(variableValue: Double, configuration: UIImage.Configuration? = nil) -> UIImage {
        UIImage(systemName: self.rawValue, variableValue: variableValue, configuration: configuration)!
    }

    @available(iOS 13.0, *)
    @available(macCatalyst 13.1, *)
    @available(tvOS 13.0, *)
    func uiImage(compatibleWith traitCollection: UITraitCollection?) -> UIImage {
        UIImage(systemName: self.rawValue, compatibleWith: traitCollection)!
    }
    #elseif canImport (AppKit)
    @available(macOS 11.0, *)
    func nsImage(accessibilityDescription description: String) -> NSImage {
        NSImage(systemSymbolName: self.rawValue, accessibilityDescription: description)!
    }

    @available(macOS 13.0, *)
    func nsImage(variableValue value: Double, accessibilityDescription description: String?) -> NSImage {
        NSImage(systemSymbolName: self.rawValue, variableValue: value, accessibilityDescription: description)!
    }
    #endif
}

Or use Array:

import SFSymbolsGenerator
import SwiftUI

// Default AccessLevel is `.internal`
#SFSymbol(accessLevel: .public, names: [
    "star",
    "case",
    "star.square.on.square",
])

Expanded source:

public enum SFSymbol: String {
    // ...
}

Type-Safe

Checks validity:

Valid
Empty
Screenshot 2023-07-23 at 13 26 20

Installation

Add the following line to the dependencies in Package.swift, to use the SFSymbol macro in a SPM project:

.package(url: "https://github.com/zijievv/sf-symbols-generator", from: "1.2.0"),

In your target:

.target(name: "<TARGET_NAME>", dependencies: [
    .product(name: "SFSymbolsGenerator", package: "sf-symbols-generator"),
    // ...
]),

Add import SFSymbolsGenerator into your source code to use the SFSymbol macro.

Xcode

Go to File > Add Package Dependencies... and paste the repo's URL:

https://github.com/zijievv/sf-symbols-generator