Skip to content

Commit bc4319e

Browse files
authored
Add alpha design token types (#2564)
<!-- How to write a good PR title: - Follow [the Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). - Give as much context as necessary and as little as possible - Prefix it with [WIP] while it’s a work in progress --> ## Self Checklist - [x] I wrote a PR title in **English** and added an appropriate **label** to the PR. - [x] I wrote the commit message in **English** and to follow [**the Conventional Commits specification**](https://www.conventionalcommits.org/en/v1.0.0/). - [x] I [added the **changeset**](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md) about the changes that needed to be released. (or didn't have to) - [x] I wrote or updated **documentation** related to the changes. (or didn't have to) - [x] I wrote or updated **tests** related to the changes. (or didn't have to) - [x] I tested the changes in various browsers. (or didn't have to) - Windows: Chrome, Edge, (Optional) Firefox - macOS: Chrome, Edge, Safari, (Optional) Firefox ## Related Issue <!-- Please link to issue if one exists --> - #2148 ## Summary <!-- Please brief explanation of the changes made --> - 알파 버전의 디자인 토큰 타입을 추가합니다 - 알파 버전의 디자인 토큰 프로바이더와 관련 훅, 토큰 객체를 export 합니다. ## Details <!-- Please elaborate description of the changes --> - `alphaTokens` 로 토큰 객체에, `AlphaTokens` 네임스페이스로 토큰 타입에 접근할 수 있도록 합니다. - `useAlphaTokens` 훅으로 자바스크립트에서 현재 테마명에 맞는 알파 버전 디자인 토큰에 접근할 수 있습니다. - `ThemeProvider` 도 `AlphaThemeProvider` 를 별도로 두어야하나 고민했지만, 이미 알파 디자인 토큰이 스타일 시트에 말려들어가있어서 `ThemeProvider` 하나만(= `AppProvider` 하나만) 사용하더라도 `useAlphaTokens` 훅을 사용할 수 있도록 해도 괜찮겠다고 생각했습니다. - 현재 토큰 객체 구조상, 타이핑할 때 Functional Semantic 토큰을 묶어서 지칭할 수 있는 용어가 필요한데 현재 디자인 시스템에는 따로 정의가 없습니다. 임시로 학습 비용이 최대한 적은 방향으로, 기존과 동일하게 SemanticToken 이라고 칭했습니다. ### Breaking change? (Yes/No) <!-- If Yes, please describe the impact and migration path for users --> No ## References <!-- Please list any other resources or points the reviewer should be aware of --> 없음
1 parent 7908274 commit bc4319e

File tree

11 files changed

+217
-21
lines changed

11 files changed

+217
-21
lines changed

.changeset/old-oranges-wink.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@channel.io/bezier-react': patch
3+
---
4+
5+
Export the `alphaTokens`, `AlphaTokens`, and `useAlphaTokens` modules.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use client'
2+
3+
import { useMemo } from 'react'
4+
5+
import { tokens } from '@channel.io/bezier-tokens/alpha'
6+
7+
import { type ThemeName } from '~/src/types/tokens'
8+
import { createContext } from '~/src/utils/react'
9+
10+
import {
11+
type ThemeSpecificTokens,
12+
type TokenContextValue,
13+
type TokenProviderProps,
14+
} from './TokenProvider.types'
15+
16+
const [TokenContextProvider, useTokenContext] =
17+
// FIXME: (@ed) Remove Alpha prefix after the migration is done
18+
createContext<TokenContextValue | null>(null, 'AlphaTokenProvider')
19+
20+
export { useTokenContext as useAlphaTokenContext }
21+
22+
const tokenSet: Record<ThemeName, ThemeSpecificTokens> = Object.freeze({
23+
light: {
24+
global: tokens.global,
25+
semantic: tokens.lightTheme,
26+
},
27+
dark: {
28+
global: tokens.global,
29+
semantic: tokens.darkTheme,
30+
},
31+
})
32+
33+
/**
34+
* @private
35+
*/
36+
export function TokenProvider({ themeName, children }: TokenProviderProps) {
37+
return (
38+
<TokenContextProvider
39+
value={useMemo(
40+
() => ({
41+
themeName,
42+
tokens: tokenSet[themeName],
43+
}),
44+
[themeName]
45+
)}
46+
>
47+
{children}
48+
</TokenContextProvider>
49+
)
50+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
type GlobalToken,
3+
type SemanticToken,
4+
type ThemeName,
5+
} from '~/src/types/alpha-tokens'
6+
7+
export interface ThemeSpecificTokens {
8+
global: GlobalToken
9+
semantic: SemanticToken
10+
}
11+
12+
export interface TokenContextValue {
13+
themeName: ThemeName
14+
tokens: ThemeSpecificTokens
15+
}
16+
17+
export interface TokenProviderProps {
18+
themeName: ThemeName
19+
children: React.ReactNode
20+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export {
2+
TokenProvider as AlphaTokenProvider,
3+
useAlphaTokenContext,
4+
} from './TokenProvider'
5+
export type { TokenProviderProps as AlphaTokenProviderProps } from './TokenProvider.types'

packages/bezier-react/src/components/AppProvider/AppProvider.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useEffect } from 'react'
44

55
import { getWindow } from 'ssr-window'
66

7+
import { AlphaTokenProvider } from '~/src/components/AlphaTokenProvider'
78
import { FeatureProvider } from '~/src/components/FeatureProvider'
89
import { TokenProvider } from '~/src/components/TokenProvider'
910
import { WindowProvider } from '~/src/components/WindowProvider'
@@ -52,7 +53,11 @@ export function AppProvider({
5253
return (
5354
<WindowProvider window={window}>
5455
<FeatureProvider features={features}>
55-
<TokenProvider themeName={themeName}>{children}</TokenProvider>
56+
<TokenProvider themeName={themeName}>
57+
<AlphaTokenProvider themeName={themeName}>
58+
{children}
59+
</AlphaTokenProvider>
60+
</TokenProvider>
5661
</FeatureProvider>
5762
</WindowProvider>
5863
)

packages/bezier-react/src/components/ThemeProvider/ThemeProvider.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { forwardRef } from 'react'
44

55
import { Slot } from '@radix-ui/react-slot'
66

7+
import {
8+
AlphaTokenProvider,
9+
useAlphaTokenContext,
10+
} from '~/src/components/AlphaTokenProvider'
711
import { TokenProvider, useTokenContext } from '~/src/components/TokenProvider'
812

913
import {
@@ -25,6 +29,14 @@ export function useTokens() {
2529
return useTokenContext('useTokens').tokens
2630
}
2731

32+
/**
33+
* `useAlphaTokens` is a hook that returns the alpha tokens of the current theme.
34+
* @internal
35+
*/
36+
export function useAlphaTokens() {
37+
return useAlphaTokenContext('useAlphaTokens').tokens
38+
}
39+
2840
/**
2941
* `ThemeProvider` is a wrapper component that provides theme context.
3042
*
@@ -34,14 +46,16 @@ export const ThemeProvider = forwardRef<HTMLElement, ThemeProviderProps>(
3446
function ThemeProvider({ themeName, children, ...rest }, forwardedRef) {
3547
return (
3648
<TokenProvider themeName={themeName}>
37-
<Slot
38-
ref={forwardedRef}
39-
// TODO: Change data attribute constant to import from bezier-tokens
40-
data-bezier-theme={themeName}
41-
{...rest}
42-
>
43-
{children}
44-
</Slot>
49+
<AlphaTokenProvider themeName={themeName}>
50+
<Slot
51+
ref={forwardedRef}
52+
// TODO: Change data attribute constant to import from bezier-tokens
53+
data-bezier-theme={themeName}
54+
{...rest}
55+
>
56+
{children}
57+
</Slot>
58+
</AlphaTokenProvider>
4559
</TokenProvider>
4660
)
4761
}

packages/bezier-react/src/components/ThemeProvider/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export {
55
ThemeProvider,
66
useThemeName,
77
useTokens,
8+
useAlphaTokens,
89
} from './ThemeProvider'
910
export {
1011
type FixedThemeProviderProps,

packages/bezier-react/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import '~/src/styles/index.scss'
33

44
/* --------------------------------- TOKENS --------------------------------- */
55
export { tokens } from '@channel.io/bezier-tokens'
6+
export { tokens as alphaTokens } from '@channel.io/bezier-tokens/alpha'
67

78
/* ------------------------------- COMPONENTS ------------------------------- */
89
export * from '~/src/components/AlphaAvatar'
@@ -78,3 +79,4 @@ export * from '~/src/hooks/useKeyboardActionLockerWhileComposing'
7879
/* ---------------------------------- TYPES --------------------------------- */
7980
export type * from '~/src/types/props'
8081
export type * from '~/src/types/tokens'
82+
export type * as AlphaTokens from '~/src/types/alpha-tokens'
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { type tokens } from '@channel.io/bezier-tokens/alpha'
2+
3+
import {
4+
type ExtractKeys,
5+
type RemovePrefix,
6+
type StartsWithPrefix,
7+
} from './utils'
8+
9+
// TODO: Change theme name constant to import from bezier-tokens
10+
export type ThemeName = 'light' | 'dark'
11+
12+
export type GlobalToken = typeof tokens.global
13+
/**
14+
* FIXME: Separate functional and semantic tokens?
15+
*/
16+
export type SemanticToken = typeof tokens.lightTheme | typeof tokens.darkTheme
17+
18+
// NOTE: (@ed) Do not remove alpha- prefix to match CSS variable names
19+
export type FlattenGlobalToken = ExtractKeys<GlobalToken[keyof GlobalToken]>
20+
export type FlattenSemanticToken = ExtractKeys<
21+
SemanticToken[keyof SemanticToken]
22+
>
23+
export type FlattenAllToken = FlattenGlobalToken | FlattenSemanticToken
24+
25+
export type GlobalColor = RemovePrefix<
26+
'alpha-color',
27+
keyof GlobalToken['color']
28+
>
29+
30+
/**
31+
* Functional & Semantic color tokens
32+
*/
33+
export type BaseSemanticColor = RemovePrefix<
34+
'alpha-color',
35+
keyof SemanticToken['color']
36+
>
37+
38+
export type BackgroundFunctionalColor = StartsWithPrefix<
39+
'bg',
40+
BaseSemanticColor
41+
>
42+
export type ForegroundFunctionalColor = StartsWithPrefix<
43+
'fg',
44+
BaseSemanticColor
45+
>
46+
export type SurfaceFunctionalColor = StartsWithPrefix<
47+
'surface',
48+
BaseSemanticColor
49+
>
50+
export type ShadowFunctionalColor = StartsWithPrefix<
51+
'shadow',
52+
BaseSemanticColor
53+
>
54+
export type DimFunctionalColor = StartsWithPrefix<'dim', BaseSemanticColor>
55+
56+
export type FunctionalColor =
57+
| BackgroundFunctionalColor
58+
| ForegroundFunctionalColor
59+
| SurfaceFunctionalColor
60+
| ShadowFunctionalColor
61+
| DimFunctionalColor
62+
63+
export type SemanticColor = StartsWithPrefix<
64+
'primary' | 'critical' | 'warning' | 'accent' | 'success',
65+
BaseSemanticColor
66+
>
67+
68+
export type Color = GlobalColor | FunctionalColor | SemanticColor
69+
70+
export type Radius = RemovePrefix<'alpha-radius', keyof GlobalToken['radius']>
71+
export type Opacity = RemovePrefix<
72+
'alpha-opacity',
73+
keyof GlobalToken['opacity']
74+
>
75+
export type Font = RemovePrefix<'alpha-font', keyof GlobalToken['font']>
76+
export type Typography = RemovePrefix<
77+
'alpha-typography',
78+
keyof GlobalToken['typography']
79+
>
80+
export type GlobalGradient = RemovePrefix<
81+
'alpha-gradient',
82+
keyof GlobalToken['gradient']
83+
>
84+
85+
export type Shadow = RemovePrefix<'alpha-shadow', keyof SemanticToken['shadow']>
86+
export type FunctionalGradient = RemovePrefix<
87+
'alpha-gradient',
88+
keyof SemanticToken['gradient']
89+
>

packages/bezier-react/src/types/tokens.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
import { type tokens } from '@channel.io/bezier-tokens'
22

3-
type RemovePrefix<
4-
Prefix extends string,
5-
Value extends string,
6-
> = Value extends `${Prefix}-${infer Rest}` ? Rest : never
7-
8-
type StartsWithPrefix<
9-
Prefix extends string,
10-
Value extends string,
11-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
12-
> = Value extends `${Prefix}-${infer Rest}` ? Value : never
13-
14-
type ExtractKeys<T> = T extends Record<infer K, any> ? K : never
3+
import {
4+
type ExtractKeys,
5+
type RemovePrefix,
6+
type StartsWithPrefix,
7+
} from './utils'
158

169
// TODO: Change theme name constant to import from bezier-tokens
1710
export type ThemeName = 'light' | 'dark'

0 commit comments

Comments
 (0)