diff --git a/.changeset/fuzzy-kangaroos-cover.md b/.changeset/fuzzy-kangaroos-cover.md new file mode 100644 index 00000000000..31f2ec8bf08 --- /dev/null +++ b/.changeset/fuzzy-kangaroos-cover.md @@ -0,0 +1,6 @@ +--- +"@primer/react": patch +"@primer/styled-react": patch +--- + +chore: forward @primer/react theming from @primer/styled-react under FF diff --git a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts index 979363503f2..3331554c772 100644 --- a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts +++ b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts @@ -4,4 +4,5 @@ export const DefaultFeatureFlags = FeatureFlagScope.create({ primer_react_css_anchor_positioning: false, primer_react_select_panel_fullscreen_on_narrow: false, primer_react_select_panel_order_selected_at_top: false, + primer_react_styled_react_use_primer_theme_providers: false, }) diff --git a/packages/styled-react/src/__tests__/FeatureFlaggedTheming.browser.test.tsx b/packages/styled-react/src/__tests__/FeatureFlaggedTheming.browser.test.tsx new file mode 100644 index 00000000000..9a90901e6a2 --- /dev/null +++ b/packages/styled-react/src/__tests__/FeatureFlaggedTheming.browser.test.tsx @@ -0,0 +1,127 @@ +import {render, screen} from '@testing-library/react' +import {describe, expect, it, vi} from 'vitest' +import React from 'react' +import {ThemeProvider, useTheme, BaseStyles} from '../' +import {FeatureFlags} from '@primer/react/experimental' + +// window.matchMedia() is not implemented by JSDOM so we have to create a mock: +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}) + +describe('FeatureFlaggedTheming', () => { + describe('when primer_react_styled_react_use_primer_theme_providers is disabled', () => { + it('ThemeProvider does not render a wrapper div with data-color-mode', () => { + render( + + +
Hello
+
+
, + ) + + // The styled ThemeProvider uses styled-components SCThemeProvider which + // does not inject a wrapper div. The child should not have a parent with data-color-mode. + const child = screen.getByTestId('child') + expect(child.parentElement).not.toHaveAttribute('data-color-mode') + }) + + it('useTheme returns styled theme context values', () => { + function ThemeConsumer() { + const theme = useTheme() + return
{theme.colorMode ?? 'day'}
+ } + + render( + + + + + , + ) + + expect(screen.getByTestId('theme-consumer')).toHaveTextContent('night') + }) + + it('BaseStyles renders with data-color-mode and without data-component', () => { + render( + + + +
Hello
+
+
+
, + ) + + const baseStyles = screen.getByTestId('base-styles') + expect(baseStyles).toHaveAttribute('data-color-mode') + expect(baseStyles).toHaveAttribute('data-light-theme') + expect(baseStyles).toHaveAttribute('data-dark-theme') + expect(baseStyles).not.toHaveAttribute('data-component') + }) + }) + + describe('when primer_react_styled_react_use_primer_theme_providers is enabled', () => { + it('ThemeProvider renders a wrapper div with data-color-mode', () => { + render( + + +
Hello
+
+
, + ) + + // The @primer/react ThemeProvider renders a
with data-color-mode + const child = screen.getByTestId('child') + expect(child.parentElement).toHaveAttribute('data-color-mode') + expect(child.parentElement).toHaveAttribute('data-light-theme') + expect(child.parentElement).toHaveAttribute('data-dark-theme') + }) + + it('useTheme returns primer theme context values', () => { + function ThemeConsumer() { + const theme = useTheme() + return
{theme.colorMode ?? 'day'}
+ } + + render( + + + + + , + ) + + expect(screen.getByTestId('theme-consumer')).toHaveTextContent('night') + }) + + it('BaseStyles renders with data-component and without data-color-mode', () => { + render( + + + +
Hello
+
+
+
, + ) + + const baseStyles = screen.getByTestId('base-styles') + expect(baseStyles).toHaveAttribute('data-component', 'BaseStyles') + expect(baseStyles).not.toHaveAttribute('data-color-mode') + expect(baseStyles).not.toHaveAttribute('data-light-theme') + expect(baseStyles).not.toHaveAttribute('data-dark-theme') + }) + }) +}) diff --git a/packages/styled-react/src/components/FeatureFlaggedTheming.tsx b/packages/styled-react/src/components/FeatureFlaggedTheming.tsx new file mode 100644 index 00000000000..39b9b5f388f --- /dev/null +++ b/packages/styled-react/src/components/FeatureFlaggedTheming.tsx @@ -0,0 +1,47 @@ +import type React from 'react' +import { + ThemeProvider as PrimerThemeProvider, + useTheme as primerUseTheme, + BaseStyles as PrimerBaseStyles, +} from '@primer/react' +import type { + ThemeProviderProps as PrimerThemeProviderProps, + BaseStylesProps as PrimerBaseStylesProps, +} from '@primer/react' +import {useFeatureFlag} from '@primer/react/experimental' +import {ThemeProvider as StyledThemeProvider, useTheme as styledUseTheme, useColorSchemeVar} from './ThemeProvider' +import type {ThemeProviderProps as StyledThemeProviderProps} from './ThemeProvider' +import {BaseStyles as StyledBaseStyles} from './BaseStyles' +import type {BaseStylesProps as StyledBaseStylesProps} from './BaseStyles' + +export type ThemeProviderProps = StyledThemeProviderProps + +export type BaseStylesProps = StyledBaseStylesProps + +export const ThemeProvider: React.FC> = ({children, ...props}) => { + const enabled = useFeatureFlag('primer_react_styled_react_use_primer_theme_providers') + if (enabled) { + return {children} + } + return {children} +} + +export function useTheme() { + const enabled = useFeatureFlag('primer_react_styled_react_use_primer_theme_providers') + const styledTheme = styledUseTheme() + const primerTheme = primerUseTheme() + if (enabled) { + return primerTheme + } + return styledTheme +} + +export {useColorSchemeVar} + +export function BaseStyles(props: BaseStylesProps) { + const enabled = useFeatureFlag('primer_react_styled_react_use_primer_theme_providers') + if (enabled) { + return + } + return +} diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index 7b2aa90ed8b..a627c18748c 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -39,7 +39,7 @@ export { * `@primer/primitives` and CSS Modules instead. */ type ThemeProviderProps, -} from './components/ThemeProvider' +} from './components/FeatureFlaggedTheming' export { /** @@ -53,7 +53,7 @@ export { * supported. Use the component from `@primer/react` with CSS Modules instead. */ type BaseStylesProps, -} from './components/BaseStyles' +} from './components/FeatureFlaggedTheming' export { /**