Bug 1855320 Comment 0 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

# WIP draft

The theming systems on Fenix have been baking since 2021 and it'd benefit the UI in Android Components (and likely Focus) if we could use the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

#### In a partnership with Design, the goals would be the following:

1. The color tokens are usable in AC.
2. The color theming is still extensible (i.e. any number of themes could be theoretically added).
3. The typography tokens are usable in AC.
4. The top-level components are usable in AC.

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
# WIP draft

The theming systems on Fenix have been baking since 2021 and it'd benefit the UI in Android Components (and likely Focus) if we could use the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

#### In a partnership with Design, the goals would be the following:

1. The color tokens are usable in AC.
2. The color theming is still extensible (i.e. any number of themes could be theoretically added).
3. The typography tokens are usable in AC.
4. The top-level components are usable in AC.

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus.
# WIP draft


# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color theming is still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private.
- Focus would provide it's own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overriden 

#### In practice

##### Theme set-up
```
object AcornTheme {
    val colors: AcornColors
        @Composable  
			  get() = localAcornColors.current

    val colors: AcornTypography
        @Composable  
			  get() = localAcornTypography.current  
}

@Composable  
fun AcornTheme(  
    theme: Theme = Theme.getTheme(),
    typography: AcornTypography = AcornTypography.default(),
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        localAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

##### Firefox
```
@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> lightColorPalette  
      Theme.Dark -> darkColorPalette  
      Theme.Private -> privateColorPalette  
  }  
  
    AcornTheme(
        colors = colors,
    ) {
        content()
    }
}

@Composable
fun SomeTopLevelComposable() {
    FirefoxTheme {
       ...
       color = AcornTheme.colors.layer1,
    }
}
```
# WIP draft



# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

#### In practice

##### Theme set-up
```
object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = FirefoxColors(...)

val darkColorPalette = FirefoxColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

##### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

##### Focus
```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# WIP draft



# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

#### In practice

##### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

##### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

##### Focus
```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# WIP draft



# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

#### In practice

##### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

##### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

##### Focus

Creating a theme wrapper is optional (and more for naming), but demonstrated here for example. The alternative would be simply creating `focusColorPalette` and passing it down to the `AcornTheme` composable wrapper.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# WIP draft



# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

#### In practice

##### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

##### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

##### Focus

Creating a theme wrapper is optional (and more for naming), but demonstrated here for example. The alternative would be simply creating `focusColorPalette` and passing it down to the `AcornTheme` composable wrapper.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# WIP draft



# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private palettes.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

### In practice

#### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

#### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

#### Focus

Creating a theme wrapper is optional (and more for naming), but demonstrated here for example. The alternative would be simply creating `focusColorPalette` and passing it down to the `AcornTheme` composable wrapper.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private palettes.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

### In practice

#### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

#### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

#### Focus

Creating a theme wrapper is optional (and more for naming), but demonstrated here for example. The alternative would be simply creating `focusColorPalette` and passing it down to the `AcornTheme` composable wrapper.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
```
# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private palettes.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

### In practice

#### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

#### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

#### Focus

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
``
# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private palettes.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

### In practice

#### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

#### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

#### Focus
In this example, the `FocusTheme` singleton doesn't need to be made unless we explicitly wanted the theme calls to be `FocusTheme.colors` instead of `AcornTheme.colors`.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
``
# Design System Upstream to Android Components

## Introduction

The theming systems on Fenix have been baking since 2021, and it'd benefit the UI in Android Components, Focus, and potentially other apps at Mozilla if we could share the color tokens, typography tokens, and top-level components we've been implementing as part of the [Acorn design system](https://acorn.firefox.com/latest/acorn-aRSAh0Sp).

## Motivation

In a world where Composable components are reusable, themes are extensible, and colors and typography are , it becomes all the more important to broaden their accessibility through our code levels and . To that end, the `FirefoxTheme` wrapper and all of our components in Fenix should be migrated to Android Components. All existing Android apps under the Firefox Android team and future Mozilla Android apps would then have access to a robust theming and component system. Several goals are highlighted below, but it would be essential for the theming to be as plug-and-play as possible, similar to the `MaterialTheme` wrapper Google provides where apps can opt-in to as much or as little of the system when writing UI code. 

Ultimately, we want to bolster our relationship with Design and make all future UI implementations at the Fenix, Focus, and AC level as seamless as possible. By having a centralized theming system, we can provide ourselves (and our community) with a one-stop-shop of the Android implementation of the Acorn design system with robust, customizable themes and components.

## Goals

- The theming system is entirely self-contained in its own module.
- The theming system is extensible (i.e. the existing `FirefoxTheme` can live on top of it).
- The color tokens are now usable in AC and Focus.
- The color palettes are still extensible (i.e. any number of themes/color palettes could be theoretically slotted-in).
- The typography tokens are now usable in AC and Focus.
- The top-level components are usable in AC and Focus.
- The components would be refactored to have theme defaults from the Acorn system, but would be extensible.
- Any further enhancements to the design system are available to all consumers (e.g. grid system).
- Minimal refactoring within Fenix.

## Implementation from a high-level

### Usage

Currently we can do the following in Fenix:
```
FirefoxTheme {
   ...
   color = FirefoxTheme.colors.layer1,
}
```

The idea would be to now be able to do:
```
AcornTheme {
   ...
   color = AcornTheme.colors.layer1,
}
```
within AC, Fenix, and Focus, and be able to extend off of `AcornTheme` as needed/desired.

### Extensibility

#### Colors
- The theme wrapper would, by default, have a light and dark palette implemented.
- Firefox would override this and pass down light, dark, and private palettes.
- Focus would provide its own custom color palette.

#### Typography
Similar to colors, there would be defaults provided via `AcornTheme`, but this could be overridden.

#### App-specific global singletons
- Apps can create singletons that fulfill a unique use case for that app.
- This allows the consumers of `AcornTheme` to subscribe to whatever they want and add anything further they need.
     - Maybe Focus gets a unique shape system, or we prototype a grid-sizing system in `FirefoxTheme` before upstreaming it to `AcornTheme`.

### In practice

#### Theme set-up
```
class AcornColors(
    layer1: Color,
    ...
)


object AcornTheme {
    val colors: AcornColors
        @Composable  
        get() = LocalAcornColors.current

    val colors: AcornTypography
        @Composable
        get() = LocalAcornTypography.current  
}

internal val LocalColors = staticCompositionLocalOf { lightColorPalette }

internal val LocalTypography = staticCompositionLocalOf { Typography() }

val lightColorPalette = AcornColors(...)

val darkColorPalette = AcornColors(...)

@Composable  
fun AcornTheme(  
    colors: AcornColors = AcornTheme.colors,
    typography: AcornTypography = AcornTheme.typography,
    content: @Composable () -> Unit,  
) {  
    // This is taken from FirefoxTheme and MaterialTheme
    val rememberedColors = remember {  colors.copy()  }.apply { updateColorsFrom(colors) }
    CompositionLocalProvider(
        LocalAcornColors provides rememberColors
        LocalTypography provides typography
    ) {
        MaterialTheme(  
            content = content,  
        )  
    }  
}
```

#### Firefox
```
object FirefoxTheme {
    val colors: AcornColors
        @Composable  
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val privateColorPalette = darkColorPalette.copy(...)

@Composable  
fun FirefoxTheme(  
    theme: Theme = Theme.getTheme(),  
    content: @Composable () -> Unit,  
) {  
    val colors = when (theme) {  
      Theme.Light -> AcornTheme.lightColorPalette  
      Theme.Dark -> AcornTheme.darkColorPalette  
      Theme.Private -> FirefoxTheme.privateColorPalette  
    }
  
    AcornTheme(
        colors = colors,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FirefoxTheme {
       Text(
           text = "Hello world",
           color = FirefoxTheme.colors.textPrimary,
       )
    }
}
```

#### Focus
In this example, the `FocusTheme` singleton doesn't need to be made unless we explicitly wanted the theme calls to be `FocusTheme.colors` instead of `AcornTheme.colors`.

```
object FocusTheme {
    val colors: AcornColors
        @Composable
        get() = AcornTheme.colors

    val colors: AcornTypography
        @Composable
        get() = AcornTheme.Typography
}

private val focusColorPalette = AcornColorPalette(...) // palette from scratch

@Composable  
fun FocusTheme(
    content: @Composable () -> Unit,  
) {  
    AcornTheme(
        colors = focusColorPalette,
        content = content,
    )
}

@Composable
fun SomeComposable() {
    FocusTheme {
       Text(
           text = "Hello world",
           color = FocusTheme.colors.textPrimary,
       )
    }
}
``

Back to Bug 1855320 Comment 0