A Swift macro generating type-safe SF Symbols
@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])
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 {
// ...
}
Checks validity:
![Valid](https://private-user-images.githubusercontent.com/48703581/253987792-33b8d7de-6694-4cfe-bb3e-041c1887e515.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjAyOTY5NjYsIm5iZiI6MTcyMDI5NjY2NiwicGF0aCI6Ii80ODcwMzU4MS8yNTM5ODc3OTItMzNiOGQ3ZGUtNjY5NC00Y2ZlLWJiM2UtMDQxYzE4ODdlNTE1LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MDYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzA2VDIwMTEwNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWViNTNjMDJiODdlY2ZkNDdlY2IyMzMyN2JiOTFjNzNmZjkwNjkyMjFjMjJlMWVkMjIwN2VjZDA3NzdhZDQwODUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.jxdslOQykn_OUDABnQNArG3_kwTSN1MuGNXz0DvEiLE)
![Empty](https://private-user-images.githubusercontent.com/48703581/253988192-22245e74-7a6a-417a-ac45-63aa21d9bd0f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjAyOTY5NjYsIm5iZiI6MTcyMDI5NjY2NiwicGF0aCI6Ii80ODcwMzU4MS8yNTM5ODgxOTItMjIyNDVlNzQtN2E2YS00MTdhLWFjNDUtNjNhYTIxZDliZDBmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MDYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzA2VDIwMTEwNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTUyODI3NDI1NWEwNzQ1NzJkYzg2ZjExNjM5NTc0YTZiYTkwOGRhNjNjNmI1NTJiNmNlMzlhNDBkNjQyNGRiMWQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.DoewkItC1cyDgIsaXAV62kMNN06xZrzGssOgmW8_Mgo)
![Screenshot 2023-07-23 at 13 26 20](https://private-user-images.githubusercontent.com/48703581/255387683-f26dec82-b1d7-479d-8592-7b7dcdec9936.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjAyOTY5NjYsIm5iZiI6MTcyMDI5NjY2NiwicGF0aCI6Ii80ODcwMzU4MS8yNTUzODc2ODMtZjI2ZGVjODItYjFkNy00NzlkLTg1OTItN2I3ZGNkZWM5OTM2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MDYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzA2VDIwMTEwNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAwZDY4MGNmNDE5NmEyOTQ2NzRiOThlNDBjMjQyNjk3ZTc3YWEzMzRiZjYyNTUyMDU3Y2I2YThlOTg5YjViNTQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.XllXqG15Ch2gXpDO1M-yHNxI82gM81Zy7f3yDrrnYyE)
Swift Package Manager (SPM)
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.
Go to File > Add Package Dependencies...
and paste the repo's URL:
https://github.com/zijievv/sf-symbols-generator