Skip to content

Commit

Permalink
Add alpha design token types (#2564)
Browse files Browse the repository at this point in the history
<!--
  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 -->

없음
  • Loading branch information
sungik-choi authored Dec 17, 2024
1 parent 7908274 commit bc4319e
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/old-oranges-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@channel.io/bezier-react': patch
---

Export the `alphaTokens`, `AlphaTokens`, and `useAlphaTokens` modules.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use client'

import { useMemo } from 'react'

import { tokens } from '@channel.io/bezier-tokens/alpha'

import { type ThemeName } from '~/src/types/tokens'
import { createContext } from '~/src/utils/react'

import {
type ThemeSpecificTokens,
type TokenContextValue,
type TokenProviderProps,
} from './TokenProvider.types'

const [TokenContextProvider, useTokenContext] =
// FIXME: (@ed) Remove Alpha prefix after the migration is done
createContext<TokenContextValue | null>(null, 'AlphaTokenProvider')

export { useTokenContext as useAlphaTokenContext }

const tokenSet: Record<ThemeName, ThemeSpecificTokens> = Object.freeze({
light: {
global: tokens.global,
semantic: tokens.lightTheme,
},
dark: {
global: tokens.global,
semantic: tokens.darkTheme,
},
})

/**
* @private
*/
export function TokenProvider({ themeName, children }: TokenProviderProps) {
return (
<TokenContextProvider
value={useMemo(
() => ({
themeName,
tokens: tokenSet[themeName],
}),
[themeName]
)}
>
{children}
</TokenContextProvider>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
type GlobalToken,
type SemanticToken,
type ThemeName,
} from '~/src/types/alpha-tokens'

export interface ThemeSpecificTokens {
global: GlobalToken
semantic: SemanticToken
}

export interface TokenContextValue {
themeName: ThemeName
tokens: ThemeSpecificTokens
}

export interface TokenProviderProps {
themeName: ThemeName
children: React.ReactNode
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
TokenProvider as AlphaTokenProvider,
useAlphaTokenContext,
} from './TokenProvider'
export type { TokenProviderProps as AlphaTokenProviderProps } from './TokenProvider.types'
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useEffect } from 'react'

import { getWindow } from 'ssr-window'

import { AlphaTokenProvider } from '~/src/components/AlphaTokenProvider'
import { FeatureProvider } from '~/src/components/FeatureProvider'
import { TokenProvider } from '~/src/components/TokenProvider'
import { WindowProvider } from '~/src/components/WindowProvider'
Expand Down Expand Up @@ -52,7 +53,11 @@ export function AppProvider({
return (
<WindowProvider window={window}>
<FeatureProvider features={features}>
<TokenProvider themeName={themeName}>{children}</TokenProvider>
<TokenProvider themeName={themeName}>
<AlphaTokenProvider themeName={themeName}>
{children}
</AlphaTokenProvider>
</TokenProvider>
</FeatureProvider>
</WindowProvider>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { forwardRef } from 'react'

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

import {
AlphaTokenProvider,
useAlphaTokenContext,
} from '~/src/components/AlphaTokenProvider'
import { TokenProvider, useTokenContext } from '~/src/components/TokenProvider'

import {
Expand All @@ -25,6 +29,14 @@ export function useTokens() {
return useTokenContext('useTokens').tokens
}

/**
* `useAlphaTokens` is a hook that returns the alpha tokens of the current theme.
* @internal
*/
export function useAlphaTokens() {
return useAlphaTokenContext('useAlphaTokens').tokens
}

/**
* `ThemeProvider` is a wrapper component that provides theme context.
*
Expand All @@ -34,14 +46,16 @@ export const ThemeProvider = forwardRef<HTMLElement, ThemeProviderProps>(
function ThemeProvider({ themeName, children, ...rest }, forwardedRef) {
return (
<TokenProvider themeName={themeName}>
<Slot
ref={forwardedRef}
// TODO: Change data attribute constant to import from bezier-tokens
data-bezier-theme={themeName}
{...rest}
>
{children}
</Slot>
<AlphaTokenProvider themeName={themeName}>
<Slot
ref={forwardedRef}
// TODO: Change data attribute constant to import from bezier-tokens
data-bezier-theme={themeName}
{...rest}
>
{children}
</Slot>
</AlphaTokenProvider>
</TokenProvider>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {
ThemeProvider,
useThemeName,
useTokens,
useAlphaTokens,
} from './ThemeProvider'
export {
type FixedThemeProviderProps,
Expand Down
2 changes: 2 additions & 0 deletions packages/bezier-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import '~/src/styles/index.scss'

/* --------------------------------- TOKENS --------------------------------- */
export { tokens } from '@channel.io/bezier-tokens'
export { tokens as alphaTokens } from '@channel.io/bezier-tokens/alpha'

/* ------------------------------- COMPONENTS ------------------------------- */
export * from '~/src/components/AlphaAvatar'
Expand Down Expand Up @@ -78,3 +79,4 @@ export * from '~/src/hooks/useKeyboardActionLockerWhileComposing'
/* ---------------------------------- TYPES --------------------------------- */
export type * from '~/src/types/props'
export type * from '~/src/types/tokens'
export type * as AlphaTokens from '~/src/types/alpha-tokens'
89 changes: 89 additions & 0 deletions packages/bezier-react/src/types/alpha-tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { type tokens } from '@channel.io/bezier-tokens/alpha'

import {
type ExtractKeys,
type RemovePrefix,
type StartsWithPrefix,
} from './utils'

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

export type GlobalToken = typeof tokens.global
/**
* FIXME: Separate functional and semantic tokens?
*/
export type SemanticToken = typeof tokens.lightTheme | typeof tokens.darkTheme

// NOTE: (@ed) Do not remove alpha- prefix to match CSS variable names
export type FlattenGlobalToken = ExtractKeys<GlobalToken[keyof GlobalToken]>
export type FlattenSemanticToken = ExtractKeys<
SemanticToken[keyof SemanticToken]
>
export type FlattenAllToken = FlattenGlobalToken | FlattenSemanticToken

export type GlobalColor = RemovePrefix<
'alpha-color',
keyof GlobalToken['color']
>

/**
* Functional & Semantic color tokens
*/
export type BaseSemanticColor = RemovePrefix<
'alpha-color',
keyof SemanticToken['color']
>

export type BackgroundFunctionalColor = StartsWithPrefix<
'bg',
BaseSemanticColor
>
export type ForegroundFunctionalColor = StartsWithPrefix<
'fg',
BaseSemanticColor
>
export type SurfaceFunctionalColor = StartsWithPrefix<
'surface',
BaseSemanticColor
>
export type ShadowFunctionalColor = StartsWithPrefix<
'shadow',
BaseSemanticColor
>
export type DimFunctionalColor = StartsWithPrefix<'dim', BaseSemanticColor>

export type FunctionalColor =
| BackgroundFunctionalColor
| ForegroundFunctionalColor
| SurfaceFunctionalColor
| ShadowFunctionalColor
| DimFunctionalColor

export type SemanticColor = StartsWithPrefix<
'primary' | 'critical' | 'warning' | 'accent' | 'success',
BaseSemanticColor
>

export type Color = GlobalColor | FunctionalColor | SemanticColor

export type Radius = RemovePrefix<'alpha-radius', keyof GlobalToken['radius']>
export type Opacity = RemovePrefix<
'alpha-opacity',
keyof GlobalToken['opacity']
>
export type Font = RemovePrefix<'alpha-font', keyof GlobalToken['font']>
export type Typography = RemovePrefix<
'alpha-typography',
keyof GlobalToken['typography']
>
export type GlobalGradient = RemovePrefix<
'alpha-gradient',
keyof GlobalToken['gradient']
>

export type Shadow = RemovePrefix<'alpha-shadow', keyof SemanticToken['shadow']>
export type FunctionalGradient = RemovePrefix<
'alpha-gradient',
keyof SemanticToken['gradient']
>
17 changes: 5 additions & 12 deletions packages/bezier-react/src/types/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { type tokens } from '@channel.io/bezier-tokens'

type RemovePrefix<
Prefix extends string,
Value extends string,
> = Value extends `${Prefix}-${infer Rest}` ? Rest : never

type StartsWithPrefix<
Prefix extends string,
Value extends string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
> = Value extends `${Prefix}-${infer Rest}` ? Value : never

type ExtractKeys<T> = T extends Record<infer K, any> ? K : never
import {
type ExtractKeys,
type RemovePrefix,
type StartsWithPrefix,
} from './utils'

// TODO: Change theme name constant to import from bezier-tokens
export type ThemeName = 'light' | 'dark'
Expand Down
12 changes: 12 additions & 0 deletions packages/bezier-react/src/types/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type RemovePrefix<
Prefix extends string,
Value extends string,
> = Value extends `${Prefix}-${infer Rest}` ? Rest : never

export type StartsWithPrefix<
Prefix extends string,
Value extends string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
> = Value extends `${Prefix}-${infer Rest}` ? Value : never

export type ExtractKeys<T> = T extends Record<infer K, any> ? K : never

0 comments on commit bc4319e

Please sign in to comment.