Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/remove-react-theme-color-schemes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': major
---

ThemeProvider: Remove resolved color-scheme theme merging from `@primer/react` and stop exposing `theme.colorSchemes` on the default exported theme. Legacy color-scheme resolution remains in `@primer/styled-react`.
4 changes: 4 additions & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
"types": "./dist/test-helpers.d.ts",
"default": "./dist/test-helpers.js"
},
"./legacy-theme/ts/color-schemes": {
"types": "./dist/legacy-theme/ts/color-schemes.d.ts",
"default": "./dist/legacy-theme/ts/color-schemes.js"
},
"./generated/components.json": "./generated/components.json",
"./generated/hooks.json": "./generated/hooks.json"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/react/rolldown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const entrypoints = new Set([

// "./next"
'src/next/index.ts',

// "./legacy-theme/ts/color-schemes"
'src/legacy-theme/ts/color-schemes.ts',
])

function getEntrypointsFromInput(input: ReadonlySet<string>) {
Expand Down
1 change: 0 additions & 1 deletion packages/react/src/ThemeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export const ThemeContext = React.createContext<{
colorScheme?: string
colorMode?: ColorModeWithAuto
resolvedColorMode?: ColorMode
resolvedColorScheme?: string
dayScheme?: string
nightScheme?: string
setColorMode: React.Dispatch<React.SetStateAction<ColorModeWithAuto>>
Expand Down
40 changes: 2 additions & 38 deletions packages/react/src/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react'
import defaultTheme from './theme'
import deepmerge from 'deepmerge'
import {useSyncedState} from './hooks/useSyncedState'
import {ThemeContext} from './ThemeContext'
import {useTheme} from './useTheme'
Expand Down Expand Up @@ -48,30 +47,24 @@ export const ThemeProvider: React.FC<React.PropsWithChildren<ThemeProviderProps>
const systemColorMode = useSystemColorMode()
const resolvedColorMode = resolveColorMode(colorMode, systemColorMode)
const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme)
const {resolvedTheme, resolvedColorScheme} = React.useMemo(
() => applyColorScheme(theme, colorScheme),
[theme, colorScheme],
)

const contextValue = React.useMemo(
() => ({
theme: resolvedTheme,
theme,
colorScheme,
colorMode,
resolvedColorMode,
resolvedColorScheme,
dayScheme,
nightScheme,
setColorMode,
setDayScheme,
setNightScheme,
}),
[
resolvedTheme,
theme,
colorScheme,
colorMode,
resolvedColorMode,
resolvedColorScheme,
dayScheme,
nightScheme,
setColorMode,
Expand Down Expand Up @@ -136,33 +129,4 @@ function chooseColorScheme(colorMode: ColorMode, dayScheme: string, nightScheme:
}
}

function applyColorScheme(
theme: Theme,
colorScheme: string,
): {resolvedTheme: Theme; resolvedColorScheme: string | undefined} {
if (!theme.colorSchemes) {
return {
resolvedTheme: theme,
resolvedColorScheme: undefined,
}
}

if (!theme.colorSchemes[colorScheme]) {
// eslint-disable-next-line no-console
console.error(`\`${colorScheme}\` scheme not defined in \`theme.colorSchemes\``)

// Apply the first defined color scheme
const defaultColorScheme = Object.keys(theme.colorSchemes)[0]
return {
resolvedTheme: deepmerge(theme, theme.colorSchemes[defaultColorScheme]),
resolvedColorScheme: defaultColorScheme,
}
}

return {
resolvedTheme: deepmerge(theme, theme.colorSchemes[colorScheme]),
resolvedColorScheme: colorScheme,
}
}

export default ThemeProvider
105 changes: 0 additions & 105 deletions packages/react/src/__tests__/ThemeProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,111 +421,6 @@ describe('useColorSchemeVar', () => {
})
})

describe('useTheme().resolvedColorScheme', () => {
it('is undefined when not in a theme', () => {
const Component = () => {
const {resolvedColorScheme} = useTheme()

return <span data-testid="text">{resolvedColorScheme}</span>
}

render(<Component />)

expect(screen.getByTestId('text').textContent).toEqual('')
})

it('is the same as the applied colorScheme, when that colorScheme is in the theme', () => {
const Component = () => {
const {resolvedColorScheme} = useTheme()

return <span data-testid="text">{resolvedColorScheme}</span>
}

const schemeToApply = 'dark'

render(
<ThemeProvider colorMode="day" dayScheme={schemeToApply}>
<Component />
</ThemeProvider>,
)

expect(screen.getByTestId('text').textContent).toEqual(schemeToApply)
})

it('is the value of the fallback colorScheme applied when attempting to apply an invalid colorScheme', () => {
const spy = vi.spyOn(console, 'error').mockImplementationOnce(() => {})
const Component = () => {
const {resolvedColorScheme} = useTheme()

return <span data-testid="text">{resolvedColorScheme}</span>
}

const schemeToApply = 'totally-invalid-colorscheme'
render(
<ThemeProvider colorMode="day" dayScheme={schemeToApply}>
<Component />
</ThemeProvider>,
)

const defaultThemeColorScheme = 'light'

expect(spy).toHaveBeenCalledWith('`totally-invalid-colorscheme` scheme not defined in `theme.colorSchemes`')
expect(defaultThemeColorScheme).not.toEqual(schemeToApply)
expect(screen.getByTestId('text').textContent).toEqual(defaultThemeColorScheme)

spy.mockRestore()
})

describe('nested theme', () => {
it('is the same as the applied colorScheme, when that colorScheme is in the theme', () => {
const Component = () => {
const {resolvedColorScheme} = useTheme()

return <span data-testid="text">{resolvedColorScheme}</span>
}

const schemeToApply = 'dark'

render(
<ThemeProvider colorMode="day" dayScheme={schemeToApply}>
<ThemeProvider>
<Component />
</ThemeProvider>
</ThemeProvider>,
)

expect(screen.getByTestId('text').textContent).toEqual(schemeToApply)
})

it('is the value of the fallback colorScheme applied when attempting to apply an invalid colorScheme', () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})

const Component = () => {
const {resolvedColorScheme} = useTheme()

return <span data-testid="text">{resolvedColorScheme}</span>
}

const schemeToApply = 'totally-invalid-colorscheme'
render(
<ThemeProvider colorMode="day" dayScheme={schemeToApply}>
<ThemeProvider>
<Component />
</ThemeProvider>
</ThemeProvider>,
)

const defaultThemeColorScheme = 'light'

expect(spy).toHaveBeenCalledWith('`totally-invalid-colorscheme` scheme not defined in `theme.colorSchemes`')
expect(defaultThemeColorScheme).not.toEqual(schemeToApply)
expect(screen.getByTestId('text').textContent).toEqual(defaultThemeColorScheme)

spy.mockRestore()
})
})
})

describe('contextOnly', () => {
it('renders a div with data-* attributes by default', () => {
const {container} = render(
Expand Down
2 changes: 0 additions & 2 deletions packages/react/src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type {KeyPaths} from './utils/types/KeyPaths'
import {fontStack} from './utils/theme'
import {colorSchemes} from './legacy-theme/ts/color-schemes'

const animation = {
easeOutCubic: 'cubic-bezier(0.33, 1, 0.68, 1)',
Expand Down Expand Up @@ -69,7 +68,6 @@ const theme = {
radii,
sizes,
space,
colorSchemes,
}

export default theme
Expand Down
5 changes: 0 additions & 5 deletions packages/react/src/utils/useTheme.hookDocs.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@
"type": "'auto' | 'day' | 'night' | 'light' | 'dark'",
"description": "The color mode (for example: \"day\", \"night\") that is applied. If the color mode is \"auto\", the color mode is determined by the user's system preference."
},
{
"name": "resolvedColorScheme",
"type": "string",
"description": "The name of the current color scheme."
},
{
"name": "resolvedColorMode",
"type": "'day' | 'night' | 'light' | 'dark'",
Expand Down
4 changes: 3 additions & 1 deletion packages/styled-react/src/components/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from 'react'
import {ThemeProvider as SCThemeProvider} from 'styled-components'
import {theme as defaultTheme, useId, useSyncedState} from '@primer/react'
import {colorSchemes} from '@primer/react/legacy-theme/ts/color-schemes'
import deepmerge from 'deepmerge'
import {ThemeContext} from './ThemeContext'
import {useTheme} from './useTheme'

export const defaultColorMode = 'day'
const defaultDayScheme = 'light'
const defaultNightScheme = 'dark'
const defaultThemeWithColorSchemes = {...defaultTheme, colorSchemes}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Theme = {[key: string]: any}
Expand Down Expand Up @@ -64,7 +66,7 @@ export const ThemeProvider: React.FC<React.PropsWithChildren<ThemeProviderProps>
} = useTheme()

// Initialize state
const theme = props.theme ?? fallbackTheme ?? defaultTheme
const theme = props.theme ?? fallbackTheme ?? defaultThemeWithColorSchemes

const uniqueDataId = useId()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import {useColorSchemeVar as primerUseColorSchemeVar, useTheme as primerUseTheme
import {useFeatureFlag} from '@primer/react/experimental'
import {useColorSchemeVar as styledUseColorSchemeVar, useTheme as styledUseTheme} from './useTheme'

export function useTheme(): ReturnType<typeof primerUseTheme> {
type StyledThemeData = ReturnType<typeof styledUseTheme>

export function useTheme(): StyledThemeData {
const enabled = useFeatureFlag('primer_react_styled_react_use_primer_theme_providers')
const styledTheme = styledUseTheme()
const primerTheme = primerUseTheme()
if (enabled) {
return primerTheme as ReturnType<typeof primerUseTheme>
return primerTheme as StyledThemeData
}
return styledTheme
}
Expand Down
4 changes: 4 additions & 0 deletions packages/styled-react/vitest.config.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export default defineConfig({
resolve: {
dedupe: ['react', 'react-dom'],
alias: [
{
find: '@primer/react/legacy-theme/ts/color-schemes',
replacement: path.resolve(import.meta.dirname, '..', 'react', 'src', 'legacy-theme', 'ts', 'color-schemes.ts'),
},
{
find: '@primer/react/experimental',
replacement: path.resolve(import.meta.dirname, '..', 'react', 'src', 'experimental', 'index.ts'),
Expand Down