Skip to content

Commit

Permalink
feat(Theme): add darkMode and contrastMode props (#2355)
Browse files Browse the repository at this point in the history
* Rename `colorMapping` to `propMapping` because we may map other properties as well

* feat(Theme): add ˙darkMode` and `contrastMode` props

* docs(Theme): create dedicated pages
  • Loading branch information
tujoworker committed May 31, 2023
1 parent 173b040 commit 04b350e
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 83 deletions.
13 changes: 7 additions & 6 deletions packages/dnb-design-system-portal/src/core/ChangeStyleTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
setTheme,
} from 'gatsby-plugin-eufemia-theme-handler'

export default function ChangeStyleTheme() {
export default function ChangeStyleTheme({ label = null } = {}) {
const themes = getThemes()
const { name } = getTheme()
const { update } = React.useContext(Context)
Expand All @@ -24,6 +24,7 @@ export default function ChangeStyleTheme() {
id="change-theme"
value={name}
data={date}
label={label}
on_change={({ data: { value } }) => {
update({ skeleton: true })
setTheme({ name: value }, () => {
Expand All @@ -34,17 +35,17 @@ export default function ChangeStyleTheme() {
)
}

ChangeStyleTheme.ColorMapping = ColorMapping
ChangeStyleTheme.PropMapping = PropMapping

function ColorMapping({ enabled, ...props }) {
const { colorMapping } = getTheme()
function PropMapping({ enabled, ...props }) {
const { propMapping } = getTheme()
return (
<Switch
top
label="Toggle Color Mapping"
checked={colorMapping === 'basis' || enabled}
checked={propMapping === 'basis' || enabled}
on_change={({ checked }) => {
setTheme({ colorMapping: checked ? 'basis' : null })
setTheme({ propMapping: checked ? 'basis' : null })
}}
{...props}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Strings where changed/removed and added to the [language files](/uilib/usage/cus

## New helper functions

- [useTranslation](/usage/customisation/localization#how-to-use-your-own-translation-strings) hook to consume your own translation strings.
- [useTranslation](/uilib/usage/customisation/localization#how-to-use-your-own-translation-strings) hook to consume your own translation strings.
- [InteractionInvalidation](/uilib/helpers/functions) method – used by the Modal to invalidate everything outside of the modal to be accessible for keyboard and screen readers.
- [debounce](/uilib/helpers/functions) method – used by AutoComplete to delay asynchronous typed searches.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,87 +5,33 @@ order: 7

# Theming

Theming is a umbrella term of a wide range of different ways and needs of customization.
**Table of Contents**

This section covers some of the needs we've seen in DNB productions as of now.

You may also check out the section in the contribution docs on [how to maintain and create a theme](/contribute/style-guides/theming/) or [how to deal with the brand as a developer](/brand/development/).

---

- [Theming](#theming)
- [Theming](#themes-and-theming)
- [Integrated theming](#integrated-theming)
- [Theme Component and useTheme Hook](#theme-component-and-usetheme-hook)
- [Theme Component and useTheme Hook](#theme-component-and-usetheme-hook)
- [Brand theming](#brand-theming)
- [Run your application with a different theme](#run-your-application-with-a-different-theme)
- [WIP: Ready to use themes](#wip-ready-to-use-themes)
- [Using `postcss-replace`](#using-postcss-replace)

## Integrated theming

Eufemia supports theming right inside where all the style-sources lives. Having the ability to control different styles as close to the source as possible, will make it possible to carefully handle continues improvements over time.

Themes are independent style packages, which should not be imported in parallel. But rather either – or.

### Theme Component and useTheme Hook
---

Eufemia has a theming helper, that lets us create nested theming solutions. As of now, it does not deliver any extra features beside the principle.
Theming is an umbrella term of a wide range of different ways and needs of customization.

```tsx
import { Theme, useTheme } from '@dnb/eufemia/shared'
This section covers some of the needs we've seen in DNB productions as of now.

const Component = () => {
const { name, variant } = useTheme()
return 'My Component'
}
You may also check out the section in the contribution docs on [how to maintain and create a theme](/contribute/style-guides/theming/) or [how to deal with the brand as a developer](/brand/development/).

render(
<Theme name="theme-name" variant="theme-variant">
<Component />
</Theme>
)
```
## Integrated theming

In addition, you can use this helper function to show/hide content based on the theme.

```tsx
import { Theme, VisibilityByTheme } from '@dnb/eufemia/shared'

render(
<Theme>
<VisibilityByTheme visible="sbanken">
Only shown in Sbanken theme
</VisibilityByTheme>

<VisibilityByTheme hidden="eiendom">
Only hidden in Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme visible={['sbanken', 'eiendom']}>
Only shown in Sbanken or Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme
visible={[{ name: 'sbanken' }, { name: 'eiendom' }]}
>
Only shown in Sbanken or Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme
visible={[{ name: 'sbanken' }, { name: 'eiendom', variant: 'blue' }]}
>
Only shown in Sbanken then or Eiendom theme – that also includes the
fictive variant="blue".
</VisibilityByTheme>
</Theme>
)
```
Eufemia supports theming right inside where all the style-sources lives. Having the ability to control different styles as close to the source as possible, will make it possible to carefully handle continuous improvements over time.

`<Theme>` Will create a `div` wrapper by default, when no custom element is defined (`element="span"`). It sets these CSS classes:
Themes are independent style packages, which should not be imported in parallel. But rather either – or.

- `eufemia-theme__{theme-name}`
- `eufemia-theme__{theme-name}--{theme-variant}`
### Theme Component and useTheme Hook

Eufemia has [theming helpers](/uilib/usage/customisation/theming/theme), that lets you create nested theming solutions.

### Brand theming

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: 'Theme'
description: 'The Theme component is a helper component that lets you create nested theming solutions.'
showTabs: true
tabs:
- title: Info
key: '/info'
- title: Demos
key: '/demos'
- title: Properties
key: '/properties'
---

import ThemeInfo from 'Docs/uilib/usage/customisation/theming/theme/info'
import ThemeDemos from 'Docs/uilib/usage/customisation/theming/theme/demos'

<ThemeInfo />
<ThemeDemos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* UI lib Component Example
*
*/

import ComponentBox from '../../../../../../shared/tags/ComponentBox'
import styled from '@emotion/styled'
import { P, Logo } from '@dnb/eufemia/src'
import { Theme } from '@dnb/eufemia/src/shared'

export const ThemeBasis = () => (
<ComponentBox scope={{ Theme }} data-visual-test="theme-basis">
{() => {
return (
<Theme name="sbanken">
<Logo size={40} />
</Theme>
)
}}
</ComponentBox>
)

export const ThemeMapping = () => (
<ComponentBox
scope={{ P, Theme }}
// data-visual-test="theme-basis"
>
{() => {
const MyMapping = styled.div`
.eufemia-theme__sbanken.eufemia-theme__prop-mapping--my-mapping {
--color-sea-green: var(--sb-color-purple-alternative);
}
`
const CustomComponent = styled(P)`
color: var(--color-sea-green);
`
return (
<MyMapping>
<Theme name="sbanken">
<Theme propMapping="my-mapping">
<CustomComponent>Text with custom color</CustomComponent>
</Theme>
</Theme>
</MyMapping>
)
}}
</ComponentBox>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
showTabs: true
---

import {
ThemeBasis,
ThemeMapping,
} from 'Docs/uilib/usage/customisation/theming/theme/Examples'
import ChangeStyleTheme from '../../../../../../core/ChangeStyleTheme'

## Demos

<ChangeStyleTheme label="Change the brand:" />

### Basis example

<ThemeBasis />

### Basis example `propMapping`

<ThemeMapping />
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
showTabs: true
---

## Description

The Theme component is a helper component that lets you create nested theming solutions.

`<Theme>` Will by default create a `div` wrapper, when no custom element is defined (e.g. `element="span"`).

```tsx
import { Theme, useTheme } from '@dnb/eufemia/shared'

const Component = () => {
const { name, propMapping } = useTheme()
return 'My Component'
}

render(
<Theme name="theme-name">
<App>
<Theme propMapping="my-class">
<MyComponent />
</Theme>
</App>
</Theme>
)
```

Will create the following HTML/CSS classes:

**Outer Theme**

- `eufemia-theme__theme-name`

**Nested Theme**

- `eufemia-theme__theme-name`
- `eufemia-theme__prop-mapping--my-class`

With that, you can create your own styles that contains the wanted style mapping.

### Mapping of properties with `propMapping`

**WIP:** This API may change in future, as it is currently under development. Please get in touch with us before you use it.

In order to change or map CSS properties, you can make use of the `propMapping` solution.

The main motivation of this feature is to provide a set of maps you can use in your app. But it lets you create your own sets as well. To do so;

1. Define an area in your app – it could be your component – and give it a declarative name:

```tsx
import { Theme } from '@dnb/eufemia/shared'

render(
<Theme propMapping="my-maps">
<MyComponent />
</Theme>
)
```

2. Define the needed CSS properties:

```css
.eufemia-theme__theme-name.eufemia-theme__prop-mapping--my-maps {
--color-sea-green: var(--sb-color-purple-alternative);
}
```

#### Use your component as the wrapper element

You can provide your component as the wrapper. This way no additional HTML Element will be created.

```tsx
import { Theme } from '@dnb/eufemia/shared'

const Component = ({ classNamem ...props }) => {
return <div className={classNamem+' more-classes'}></div>
}

render(
<Theme name="theme-name">
<App>
<Theme propMapping="my-maps" element={Component}>
...
</Theme>
</App>
</Theme>
)
```

### Hide or show parts of your component (filter)

With this helper function you show or hide content based on inherited theme properties.

```tsx
import { Theme, VisibilityByTheme } from '@dnb/eufemia/shared'

render(
<Theme name="...">
<VisibilityByTheme visible="sbanken">
Only shown in Sbanken theme
</VisibilityByTheme>

<VisibilityByTheme hidden="eiendom">
Only hidden in Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme visible={['sbanken', 'eiendom']}>
Only shown in Sbanken or Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme
visible={[{ name: 'sbanken' }, { name: 'eiendom' }]}
>
Only shown in Sbanken or Eiendom theme
</VisibilityByTheme>

<VisibilityByTheme
visible={[{ name: 'sbanken' }, { name: 'eiendom', variant: 'blue' }]}
>
Only shown in Sbanken then or Eiendom theme – that also includes the
fictive variant="blue".
</VisibilityByTheme>
</Theme>
)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
showTabs: true
---

## Properties

| Properties | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | _(optional)_ The name of a branding theme. Can be `ui` (universal identity), `eiendom` or `sbanken` |
| `size` (WIP) | _(optional)_ Will define what sizes of components are used. |
| `variant` (WIP) | _(optional)_ WIP |
| `propMapping` (WIP) | _(optional)_ Defines a specific CSS class so you get a declarative way of mapping CSS properties. A set of predefined maps will be available (WIP). |
| `contrastMode` | _(optional)_ When a component supports a contrast style, it will be used instead for the dedicated area. |
| `darkMode` | _(optional)_ When a component supports a dark mode style, it will be used instead for the dedicated area. |
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default function PortalToolsMenu({
{theme.name === 'sbanken' && (
<Space top="large">
<H2 size="small">Map colors</H2>
<ChangeStyleTheme.ColorMapping enabled={theme.colorMapping} />
<ChangeStyleTheme.PropMapping enabled={theme.propMapping} />
</Space>
)}

Expand Down
Loading

0 comments on commit 04b350e

Please sign in to comment.