Skip to content
Ghimpu Lucian Eduard edited this page Jun 2, 2022 · 3 revisions

🌗 Theme

The theme is defined by a quite complex but not really token structure.

A token is a key-value pair that describes a specific characteristic in the design system.

Example:

button.color.primary.background.enabled = Green100

These tokens are used to ensure consistency across platforms, tools, and departments in our organization.

These are mostly used inside the design system when developing components BUT can also be changed by client apps as part of a custom theme, allowing very granular changes in the theme.

By default, the design system comes with a DefaultTheme to be used right away, but there is the possibility to customize each token in client apps.

Compose

You need to define a EverliTheme as the root of your composition tree or use the DefaultTheme

ℹ️ The theme is heavily inspired by Material Theme and involves usage of Composition Local Providers.

🙏 Please have a look at these two concepts to understand how theme works in compose.

@Composable
fun EverliApp() {
    DefaultTheme() {
        // your app
    }
}

Then inside any @Composable you will have access to any token of the design system via the EverliTheme object

@Composable
fun SomeRandomComponent() {
    Text(
        text = "label",
        style = EverliTheme.typography.subtitleSemibold),
    )
}

Note: Most (if not all) components provided in the library, require you to have a defined EverliTheme to work properly.

Custom Theme

If you want to provide a custom implementation, you can just copy DefaultTheme components or implement your own EverliTheme

Copy Default Theme

val SupplyButtonTheme = DefaultButtonTheme.copy(
  color = DefaultButtonTheme.color.copy(
    primary = DefaultButtonTheme.color.primary.copy(
      fill = DefaultButtonTheme.color.primary.fill.copy(
        background = DefaultButtonTheme.color.primary.fill.background.copy(
          enabled = EverliColors.Purple100,
          pressed = purple80,
        ),
      ),
      outline = DefaultButtonTheme.color.primary.outline.copy(
        background = DefaultButtonTheme.color.primary.outline.background.copy(
          pressed = purple20,
        ),
        border = DefaultButtonTheme.color.primary.outline.border.copy(
          enabled = purple80,
        ),
      ),
      flat = DefaultButtonTheme.color.primary.flat.copy(
        background = DefaultButtonTheme.color.primary.flat.background.copy(
          pressed = purple20,
        ),
      ),
    ),
  ),
)

@Composable
fun AppWithCustomTheme() {
  EverliTheme(
    typography = DefaultTypography,
    radius = DefaultRadius,
    dimensions = DefaultDimensions,
    buttonTheme = SupplyButtonTheme,
  ) {
    // your content
  }
}

In the above example, we define a custom theme just for the Button. Note that all components of the Theme have dedicated data classes and are easily customizable via kotlin's .copy method as shown above.

Nesting Themes

Another nice advantage of Compose is that we can nest multiple themes in the same app:

@Preview
@Composable
fun InnerCustomTheme() {
  DefaultTheme {
    Column {
      // Default Theme
      EverliButton(onClick = { /*TODO*/ }, text = "Default Theme")

      // Inner custom theme
      EverliTheme(
        buttonTheme = SupplyButtonTheme,
      ) {
        EverliButton(onClick = { /*TODO*/ }, text = "Custom Theme")
      }
    }
  }
}
Screenshot 2022-06-02 at 15 51 11

Notice that the second button used a different theme just for the button, all other tokens are inherited by the parent theme. Again, all this is possible thanks to CompositionLocalProviders

This can be useful if you want a particular section of the app to use a different theme (e.g. debug area).

Clone this wiki locally