-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement multi theme feature based on data attributes #1756
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
6fdefea
feat: implement alpha bezier provider (wip)
sungik-choi 3e0fa8f
feat(styles): add color-scheme style
sungik-choi 0b4e6ea
chore(styles): add comment
sungik-choi 1c73be3
feat(styles): add base font color style
sungik-choi 9935160
feat(bezier-react): implement useToken hook
sungik-choi 244f5cf
refactor(use-token): include token set
sungik-choi 1677c2f
feat(use-tokens): add themeName value to context value and implement …
sungik-choi b0fc27b
feat: implement fixed theme providers
sungik-choi 367a0c6
feat(alpha-bezier-provider): add tooltip provider
sungik-choi 187450b
feat(alpha-bezier-provider): consider when other root elements may ex…
sungik-choi 52bc57d
feat(alpha-bezier-provider): add feature provider
sungik-choi c10dc90
refactor: rename to AlphaAppProvider
sungik-choi 58e123a
fix(styles): change html to where selector to support shadow root hos…
sungik-choi 7975f56
fix(styles): change data selector to affect all elements
sungik-choi 59158f4
refactor(alpha-app-provider): rename prop
sungik-choi 0ed795c
docs(alpha-app-provider): add jsdoc
sungik-choi 4462f81
docs: add jsdoc
sungik-choi 4c3c887
feat(root): export modules
sungik-choi 45606aa
chore(changeset): add changeset
sungik-choi dce4b9c
fix: fix typecheck error
sungik-choi e96e4de
fix: fix import path
sungik-choi c943fa1
refactor(window-provider): rm document from window provider
sungik-choi 3c98893
feat(alpha-app-provider): apply WindowProvider and add window prop
sungik-choi f2090b9
feat(alpha-app-provider): change to use ThemeProvider internally
sungik-choi f8befb7
feat(styles): rm root color scheme
sungik-choi f2faf6b
feat: back to the root element
sungik-choi 9776221
feat(theme-provider): apply the changed design token structure
sungik-choi 257b8d9
refactor(theme-provider): add Provider suffix
sungik-choi d89ea83
refactor(alpha-app-provider): change callback fn name
sungik-choi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@channel.io/bezier-react": minor | ||
--- | ||
|
||
Implement multi theme feature based on data attributes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export type { Feature } from './Feature' | ||
export { FeatureType } from './Feature' | ||
|
||
export { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React, { useEffect } from 'react' | ||
|
||
import { | ||
type Feature, | ||
FeatureProvider, | ||
} from '~/src/features' | ||
import { window as defaultWindow } from '~/src/utils/dom' | ||
|
||
import { TooltipProvider } from '~/src/components/Tooltip' | ||
|
||
import { | ||
type ThemeName, | ||
TokenProvider, | ||
} from './ThemeProvider' | ||
import { WindowProvider } from './WindowProvider' | ||
|
||
export interface AlphaAppProviderProps { | ||
children: React.ReactNode | ||
/** | ||
* Name of the theme to use for the app. | ||
* @default 'light' | ||
*/ | ||
themeName?: ThemeName | ||
/** | ||
* List of features to enable for the app. | ||
* @default [] | ||
*/ | ||
features?: Feature[] | ||
/** | ||
* Window object to use for the app. | ||
* @default window | ||
*/ | ||
window?: Window | ||
} | ||
|
||
/** | ||
* `AlphaAppProvider` is a required wrapper component that provides context for the app. | ||
* | ||
* @example | ||
* | ||
* ```tsx | ||
* import React from 'react' | ||
* import { createRoot } from 'react-dom/client' | ||
* import { AlphaAppProvider } from '@channel.io/bezier-react' | ||
* | ||
* const container = document.getElementById('root') | ||
* const root = createRoot(container) | ||
* | ||
* root.render( | ||
* <AlphaAppProvider themeName="light"> | ||
* <App /> | ||
* </AlphaAppProvider>, | ||
* ) | ||
* ``` | ||
*/ | ||
export function AlphaAppProvider({ | ||
children, | ||
themeName = 'light', | ||
features = [], | ||
window = defaultWindow, | ||
}: AlphaAppProviderProps) { | ||
useEffect(function updateRootThemeDataAttribute() { | ||
const rootElement = window.document.documentElement | ||
// TODO: Change data attribute constant to import from bezier-tokens | ||
rootElement.setAttribute('data-bezier-theme', themeName) | ||
return function cleanup() { | ||
rootElement.removeAttribute('data-bezier-theme') | ||
} | ||
}, [ | ||
window, | ||
themeName, | ||
]) | ||
|
||
return ( | ||
<WindowProvider window={window}> | ||
<FeatureProvider features={features}> | ||
<TokenProvider themeName={themeName}> | ||
<TooltipProvider> | ||
{ children } | ||
</TooltipProvider> | ||
</TokenProvider> | ||
</FeatureProvider> | ||
</WindowProvider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import React, { | ||
forwardRef, | ||
useMemo, | ||
} from 'react' | ||
|
||
import { tokens } from '@channel.io/bezier-tokens' | ||
import { Slot } from '@radix-ui/react-slot' | ||
|
||
import { createContext } from '~/src/utils/react' | ||
|
||
type Tokens = typeof tokens | ||
type GlobalTokens = Tokens['global'] | ||
type SemanticTokens = Omit<Tokens, 'global'> | ||
|
||
interface ThemedTokenSet { | ||
global: GlobalTokens | ||
semantic: SemanticTokens[keyof SemanticTokens] | ||
} | ||
|
||
// TODO: Change theme name constant to import from bezier-tokens | ||
export type ThemeName = 'light' | 'dark' | ||
|
||
interface TokenContextValue { | ||
themeName: ThemeName | ||
tokens: ThemedTokenSet | ||
} | ||
|
||
const [TokenContextProvider, useTokenContext] = createContext<TokenContextValue | null>(null, 'TokenProvider') | ||
|
||
const tokenSet: Record<ThemeName, ThemedTokenSet> = Object.freeze({ | ||
light: { | ||
global: tokens.global, | ||
semantic: tokens.lightTheme, | ||
}, | ||
dark: { | ||
global: tokens.global, | ||
semantic: tokens.darkTheme, | ||
}, | ||
}) | ||
|
||
interface TokenProviderProps { | ||
themeName: ThemeName | ||
children: React.ReactNode | ||
} | ||
|
||
/** | ||
* @private For internal use only. | ||
*/ | ||
export function TokenProvider({ | ||
themeName, | ||
children, | ||
}: TokenProviderProps) { | ||
return ( | ||
<TokenContextProvider value={useMemo(() => ({ | ||
themeName, | ||
tokens: tokenSet[themeName], | ||
}), [themeName])} | ||
> | ||
{ children } | ||
</TokenContextProvider> | ||
) | ||
} | ||
|
||
/** | ||
* `useThemeName` is a hook that returns the current theme name. | ||
*/ | ||
export function useThemeName() { | ||
return useTokenContext('useThemeName').themeName | ||
} | ||
|
||
/** | ||
* `useToken` is a hook that returns the design token for the current theme. | ||
*/ | ||
export function useToken() { | ||
return useTokenContext('useToken').tokens | ||
} | ||
|
||
export interface ThemeProviderProps { | ||
themeName: ThemeName | ||
children: React.ReactElement | ||
} | ||
|
||
export type FixedThemeProviderProps = Omit<ThemeProviderProps, 'themeName'> | ||
|
||
/** | ||
* `ThemeProvider` is a wrapper component that provides theme context. | ||
*/ | ||
export const ThemeProvider = forwardRef<HTMLElement, ThemeProviderProps>(function ThemeProvider({ | ||
themeName, | ||
children, | ||
}, forwardedRef) { | ||
return ( | ||
<TokenProvider themeName={themeName}> | ||
<Slot | ||
ref={forwardedRef} | ||
// TODO: Change data attribute constant to import from bezier-tokens | ||
data-bezier-theme={themeName} | ||
> | ||
{ children } | ||
</Slot> | ||
</TokenProvider> | ||
) | ||
}) | ||
|
||
/** | ||
* `LightThemeProvider` is a wrapper component that provides light theme context. | ||
*/ | ||
export const LightThemeProvider = forwardRef<HTMLElement, FixedThemeProviderProps>(function LightTheme({ | ||
children, | ||
}, forwardedRef) { | ||
return ( | ||
<ThemeProvider | ||
ref={forwardedRef} | ||
themeName="light" | ||
> | ||
{ children } | ||
</ThemeProvider> | ||
) | ||
}) | ||
|
||
/** | ||
* `DarkThemeProvider` is a wrapper component that provides dark theme context. | ||
*/ | ||
export const DarkThemeProvider = forwardRef<HTMLElement, FixedThemeProviderProps>(function DarkTheme({ | ||
children, | ||
}, forwardedRef) { | ||
return ( | ||
<ThemeProvider | ||
ref={forwardedRef} | ||
themeName="dark" | ||
> | ||
{ children } | ||
</ThemeProvider> | ||
) | ||
}) | ||
|
||
/** | ||
* `InvertedThemeProvider` is a wrapper component that provides inverted theme context. | ||
*/ | ||
export const InvertedThemeProvider = forwardRef<HTMLElement, FixedThemeProviderProps>(function InvertedTheme({ | ||
children, | ||
}, forwardedRef) { | ||
return ( | ||
<ThemeProvider | ||
ref={forwardedRef} | ||
themeName={useThemeName() === 'light' ? 'dark' : 'light'} | ||
> | ||
{ children } | ||
</ThemeProvider> | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,18 @@ | ||
html { | ||
:where(:root, :host) { | ||
font-size: 62.5%; // 10/16 = 0.625. Make REM calculations easier. | ||
font-family: var(--font-family-sans-kr); | ||
color: var(--txt-black-darkest); | ||
color-scheme: light; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 누락된 기본 텍스트 컬러 추가 |
||
} | ||
|
||
// TODO: Change data attribute constant to import from bezier-tokens | ||
[data-bezier-theme='light'] { | ||
color-scheme: light; | ||
} | ||
|
||
// TODO: Change data attribute constant to import from bezier-tokens | ||
[data-bezier-theme='dark'] { | ||
color-scheme: dark; | ||
} | ||
|
||
:lang(ja) { | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BezierProvider의 로직을 보면, document가 window.document와 동일하므로 제거