Skip to content

MichiganLabs/SwiftThemeUI

Repository files navigation

SwiftThemeUI

Description

This package gives you the ability to quickly and easily implement theme designs in your SwiftUI application.

Quick Start

Assuming you have a defined theme protocol...

public protocol Theme {
  var TextAccent: Color { get }
  var TextPrimary: Color { get }
  var BodyFont: Font { get }
  var CardRadius: CGFloat { get }
}

and have an implementation of that theme...

class BrandThemeLightMode : Theme {
  let TextAccent = .red
  let TextPrimary = .blue
  let BodyFont = .system(size: 12)
  let CardRadius = 12.0
}

Add a ThemeConfig.json file to the root of your target that identifies the protocol you'd like to use.

{
  "themeType": "Theme",
  "defaultMode": "BrandThemeLightMode"
}

Then, you can simply provide your theme to the ThemeManager and have it handle the rest!

struct RootView: View {
  @StateObject var manager = ThemeManager(.static(BrandThemeLightMode()))

  var body: some View {
    ContentView()
        .themeManaging(self.manager)
  }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello World")
                .foregroundColor(alias: \.TextColor)
                .font(alias: \.BodyFont)
        }
        .cornerRadius(alias: \.CardRadius)
    }
}

Detailed Usage

Changing Themes

You can change themes easily during the runtime of your application by simply setting the theme property of the ThemeManager. If you would like to have your theme follow the ColorSheme of the application, simply provide a .dynamic theme to the manager and it will automatically update to the specified theme as the system updates.

// Instantiation
@StateObject var manager = ThemeManager(.dynamic(light: BrandThemeLightMode(), dark: BrandThemeDarkMode()))

// Or, update the existing manager with a new theme
self.manager.theme = .dynamic(light: BrandThemeLightMode(), dark: BrandThemeDarkMode())

Theme Override

There are some situations where you might want a specific component to never change themes. In this situation, you can simply provide a theme object to the environment on your component and this will override the theme provided by ThemeManager.

Text("Hello World")
    .foregroundColor(alias: \.TextAccent)
    // theme override
    .environment(\.theme, BrandThemeLightMode())

Usage Without Modifiers

If you come across a situation where a modifier is not available for your intended purpose, you can still use your theme and alias tokens by gaining access to the current theme object through the use of the ThemeReader and ThemeAliasReader respecitively.

ThemeReader { theme in
  Text("Hello World")
    .foregroundColor(theme.TextAccent)
}
ThemeAliasReader(\.TextAccent) { color in
  Text("Hello World")
    .foregroundColor(color)
}

Additionally...

There is also a currentTheme environment property wrapper available to you in situations where you'd prefer to not use one of the aforementioned theme readers.

Note

Use of this property wrapper prevents the ability for you to override the theme provided by the ThemeManger in this view with the .environment view modifier in a parent view.

struct ContentView: View {
  @Environment(\.currentTheme) private var theme

  var body: some View {
    Text("Hello World")
      .foregroundColor(self.theme.TextAccent)
  }
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages