Skip to content

Commit

Permalink
feat(semantic-tokens): add support for DarkMode/LightMode components
Browse files Browse the repository at this point in the history
  • Loading branch information
TimKolberger committed Feb 26, 2022
1 parent 21e1e3a commit ac54330
Show file tree
Hide file tree
Showing 20 changed files with 333 additions and 169 deletions.
6 changes: 6 additions & 0 deletions .changeset/brown-moose-relate.md
@@ -0,0 +1,6 @@
---
"@chakra-ui/color-mode": major
---

Moved components `LightMode` and `DarkMode` to package `@chakra-ui/system` to
prevent circular dependencies.
6 changes: 6 additions & 0 deletions .changeset/mighty-monkeys-wash.md
@@ -0,0 +1,6 @@
---
"@chakra-ui/styled-system": minor
---

Updated `_dark` and `_light` pseudo selectors to allow semantic tokens to change
with the `DarkMode` and `LightMode` component.
6 changes: 3 additions & 3 deletions .changeset/twenty-cooks-visit.md
Expand Up @@ -2,6 +2,6 @@
"@chakra-ui/system": minor
---

Added `[data-css-vars-root=true]` to the CSS variables root selector. This
allows to layer the CSS variable definitions and allow the semantic tokens to
react to `data-theme="dark"` and `data-theme="light"`.
Added `[data-theme]` to the CSS variables root selector. This allows the
semantic tokens to change according to `data-theme="dark"` and
`data-theme="light"` DOM element attributes.
26 changes: 26 additions & 0 deletions .changeset/wild-shirts-smell.md
@@ -0,0 +1,26 @@
---
"@chakra-ui/color-mode": major
---

The `LightMode` and `DarkMode` components are now able to toggle semantic tokens
as well.

For backward compatibility reasons this needs to be enabled by passing the
boolean prop `withSemanticTokens`.

```tsx live=false
<DarkMode withSemanticTokens>
<chakra.div color="your-semantic-token">
This uses always the _dark value of your semantic token
</chakra.div>
</DarkMode>
```

Please note that by adding the prop `withSemanticTokens` the ColorMode
components will render a DOM element which accepts style props as usual.

```tsx
<DarkMode withSemanticTokens p="4" flex="1">
...
</DarkMode>
```
15 changes: 14 additions & 1 deletion .storybook/preview.tsx
Expand Up @@ -56,7 +56,20 @@ const withChakra = (StoryFn: Function, context: StoryContext) => {
}, [dir])

return (
<ChakraProvider theme={extendTheme({ direction: dir })}>
<ChakraProvider
theme={extendTheme({
direction: dir,
semanticTokens: {
colors: {
semantic: {
default: "red.500",
_light: "red.500",
_dark: "blue.400",
},
},
},
})}
>
<div dir={dir} id="story-wrapper" style={{ minHeight: "100vh" }}>
<ColorModeToggleBar />
<StoryFn />
Expand Down
44 changes: 2 additions & 42 deletions packages/color-mode/src/color-mode-provider.tsx
@@ -1,5 +1,5 @@
import { useEnvironment } from "@chakra-ui/react-env"
import { isBrowser, noop, __DEV__ } from "@chakra-ui/utils"
import { __DEV__, isBrowser, noop } from "@chakra-ui/utils"
import * as React from "react"
import {
addListener,
Expand All @@ -18,7 +18,7 @@ export interface ColorModeOptions {
useSystemColorMode?: boolean
}

interface ColorModeContextType {
export interface ColorModeContextType {
colorMode: ColorMode
toggleColorMode: () => void
setColorMode: (value: any) => void
Expand Down Expand Up @@ -173,46 +173,6 @@ if (__DEV__) {
ColorModeProvider.displayName = "ColorModeProvider"
}

/**
* Locks the color mode to `dark`, without any way to change it.
*/
export const DarkMode: React.FC = (props) => {
const context = React.useMemo<ColorModeContextType>(
() => ({
colorMode: "dark",
toggleColorMode: noop,
setColorMode: noop,
}),
[],
)

return <ColorModeContext.Provider value={context} {...props} />
}

if (__DEV__) {
DarkMode.displayName = "DarkMode"
}

/**
* Locks the color mode to `light` without any way to change it.
*/
export const LightMode: React.FC = (props) => {
const context = React.useMemo<ColorModeContextType>(
() => ({
colorMode: "light",
toggleColorMode: noop,
setColorMode: noop,
}),
[],
)

return <ColorModeContext.Provider value={context} {...props} />
}

if (__DEV__) {
LightMode.displayName = "LightMode"
}

/**
* Change value based on color mode.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/color-mode/test/color-mode-provider.test.tsx
@@ -1,7 +1,7 @@
import { render } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import React from "react"
import { ColorModeProvider } from "../src/color-mode-provider"
import { ColorModeProvider } from "../src"
import * as colorModeUtils from "../src/color-mode.utils"
import {
defaultThemeOptions,
Expand Down
@@ -1,5 +1,5 @@
/* eslint-disable global-require */
import React from "react"
import * as React from "react"
import { render } from "@testing-library/react"
import {
createMockStorageManager,
Expand Down
77 changes: 0 additions & 77 deletions packages/color-mode/test/dark-mode.test.tsx

This file was deleted.

6 changes: 1 addition & 5 deletions packages/color-mode/test/use-color-mode-value.test.tsx
@@ -1,11 +1,7 @@
import React from "react"
import { render, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import {
ColorModeProvider,
useColorModeValue,
useColorMode,
} from "../src/color-mode-provider"
import { ColorModeProvider, useColorModeValue, useColorMode } from "../src"
import { defaultThemeOptions } from "./utils"

const lightValue = "light-value"
Expand Down
28 changes: 7 additions & 21 deletions packages/color-mode/test/utils.tsx
@@ -1,12 +1,14 @@
import * as React from "react"
import theme from "@chakra-ui/theme"
import { screen } from "@testing-library/react"
import React from "react"
import { ColorModeOptions } from "../src/color-mode-provider"
import type { ColorMode } from "../src/color-mode.utils"
import type { StorageManager } from "../src/storage-manager"
import {
useColorMode,
ColorModeOptions,
ColorMode,
StorageManager,
} from "../src"

export const DummyComponent = () => {
const { useColorMode } = require("../src/color-mode-provider")
const { colorMode, toggleColorMode } = useColorMode()

return (
Expand All @@ -16,22 +18,6 @@ export const DummyComponent = () => {
)
}

var renderCount = 0

export const resetCounter = () => {
renderCount = 0
}

export const MemoizedComponent = React.memo(() => {
renderCount = renderCount + 1
return <div data-testid="rendered">{renderCount}</div>
})

export const RegularComponent = () => {
renderCount = renderCount + 1
return <div data-testid="rendered">{renderCount}</div>
}

export const getColorModeButton = () => screen.getByRole("button")

export const defaultThemeOptions = theme.config as Required<ColorModeOptions>
Expand Down
10 changes: 8 additions & 2 deletions packages/styled-system/src/pseudos.ts
Expand Up @@ -298,12 +298,18 @@ export const pseudoSelectors = {
* Styles for when `data-theme` is applied to any parent of
* this component or element.
*/
_dark: ".chakra-ui-dark &, [data-theme=dark] &, &[data-theme=dark]",
_dark:
".chakra-ui-dark &:not([data-theme])," +
"[data-theme=dark] &:not([data-theme])," +
"&[data-theme=dark]",
/**
* Styles for when `data-theme` is applied to any parent of
* this component or element.
*/
_light: ".chakra-ui-light &, [data-theme=light] &, &[data-theme=light]",
_light:
".chakra-ui-light &:not([data-theme])," +
"[data-theme=light] &:not([data-theme])," +
"&[data-theme=light]",
}

export type Pseudos = typeof pseudoSelectors
Expand Down
2 changes: 1 addition & 1 deletion packages/styled-system/tests/css-var.test.ts
Expand Up @@ -482,7 +482,7 @@ test("should convert semantic tokens", () => {
"--colors-red-800": "#ff0080",
"--colors-secondary": "var(--colors-red-800)",
"--colors-success": "var(--colors-red-100)",
".chakra-ui-dark &, [data-theme=dark] &, &[data-theme=dark]": Object {
".chakra-ui-dark &:not([data-theme]),[data-theme=dark] &:not([data-theme]),&[data-theme=dark]": Object {
"--colors-primary": "var(--colors-red-400)",
"--colors-secondary": "var(--colors-red-700)",
},
Expand Down

0 comments on commit ac54330

Please sign in to comment.