diff --git a/package-lock.json b/package-lock.json index 441e6a87..0a3e09e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.1.2", "@types/react": "^17.0.33", + "@types/react-dom": "^17.0.11", "@types/styled-components": "^5.1.15", "@typescript-eslint/eslint-plugin": "^4.32.0", "@typescript-eslint/parser": "^4.32.0", @@ -7203,6 +7204,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -41957,6 +41967,15 @@ "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", diff --git a/package.json b/package.json index 1ff4aba7..9a0fa26d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.1.2", "@types/react": "^17.0.33", + "@types/react-dom": "^17.0.11", "@types/styled-components": "^5.1.15", "@typescript-eslint/eslint-plugin": "^4.32.0", "@typescript-eslint/parser": "^4.32.0", diff --git a/packages/emotion/src/colorModes.test.tsx b/packages/emotion/src/colorModes.test.tsx index 1e78f859..5eb70523 100644 --- a/packages/emotion/src/colorModes.test.tsx +++ b/packages/emotion/src/colorModes.test.tsx @@ -1,37 +1,18 @@ /* eslint-env browser */ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { th } from '@xstyled/system' -import { x, ThemeProvider, ColorModeProvider } from '.' +import { cleanup } from '@testing-library/react' +import { x, ColorModeProvider } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) describe('colorModes', () => { it('supports color modes', () => { - const theme = { - defaultColorModeName: 'dark', - colors: { - black: '#000', - white: '#fff', - red: '#ff0000', - danger: th.color('red'), - text: th.color('black'), - modes: { - dark: { - red: '#ff4400', - text: th.color('white'), - }, - }, - }, - } - - render( - - - Hello - - , + renderWithTheme( + + Hello + ) expect(document.body).toHaveClass('xstyled-color-mode-dark') }) diff --git a/packages/emotion/src/createGlobalStyle.test.tsx b/packages/emotion/src/createGlobalStyle.test.tsx index d0d57903..94cfd620 100644 --- a/packages/emotion/src/createGlobalStyle.test.tsx +++ b/packages/emotion/src/createGlobalStyle.test.tsx @@ -1,16 +1,11 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { createGlobalStyle, ThemeProvider } from '.' +import { cleanup } from '@testing-library/react' +import { createGlobalStyle } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#createGlobalStyle', () => { it('injects global styles', () => { const GlobalStyle = createGlobalStyle` @@ -18,12 +13,10 @@ describe('#createGlobalStyle', () => { margin: 2; } ` - const { container } = render( + const { container } = renderWithTheme( <> - - -
- + +
, ) expect(container.firstChild).toHaveStyle(` diff --git a/packages/emotion/src/css.test.tsx b/packages/emotion/src/css.test.tsx index 8ce6d174..be922a59 100644 --- a/packages/emotion/src/css.test.tsx +++ b/packages/emotion/src/css.test.tsx @@ -1,20 +1,13 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' +import { cleanup } from '@testing-library/react' import styled from '@emotion/styled' -import { css, ThemeProvider } from '.' +import { css } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) describe('#css', () => { - const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - - {children} - - ) - } - it('transforms rules', () => { const Dummy = styled.div` ${css` @@ -23,11 +16,7 @@ describe('#css', () => { margin-top: 2px; `} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle(` margin: 2px 8px 8px 8px; padding: 4px; @@ -40,11 +29,7 @@ describe('#css', () => { margin: 1 2; `} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) @@ -55,11 +40,7 @@ describe('#css', () => { margin: 1 ${two}; `} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) @@ -69,25 +50,17 @@ describe('#css', () => { margin: '1 2', })} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) it('accepts function', () => { const Dummy = styled.div` - ${css((p) => ({ + ${css((_p) => ({ margin: '1 2', }))} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) @@ -99,11 +72,7 @@ describe('#css', () => { styles: 'margin: 1 2;label:x;', })} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) }) diff --git a/packages/emotion/src/cx.test.tsx b/packages/emotion/src/cx.test.tsx index 8539c77e..57a14621 100644 --- a/packages/emotion/src/cx.test.tsx +++ b/packages/emotion/src/cx.test.tsx @@ -2,16 +2,11 @@ import { jsx } from '@emotion/react' import '@testing-library/jest-dom/extend-expect' import { render, cleanup } from '@testing-library/react' -import { css, cx, ThemeProvider } from '.' +import { css, cx } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#cx', () => { it('throws with string value', () => { // @ts-expect-error Strings are not allowed @@ -21,18 +16,16 @@ describe('#cx', () => { }) it('handles css values', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 2px 8px 8px 8px; @@ -41,19 +34,17 @@ describe('#cx', () => { }) it('handles multiple css values', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 8px; diff --git a/packages/emotion/src/jsx.test.tsx b/packages/emotion/src/jsx.test.tsx index 01e0da50..d76619e8 100644 --- a/packages/emotion/src/jsx.test.tsx +++ b/packages/emotion/src/jsx.test.tsx @@ -1,35 +1,27 @@ /** @jsx jsx */ import '@testing-library/jest-dom/extend-expect' import { render, cleanup } from '@testing-library/react' -import { ThemeProvider } from '@emotion/react' import { jsx, css } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#jsx', () => { it('does nothing without css prop', () => { const { container } = render(
) - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') }) it('handles css string', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 2px 8px 8px 8px; @@ -38,20 +30,18 @@ describe('#jsx', () => { }) it('handles array of css string', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 8px; @@ -60,13 +50,11 @@ describe('#jsx', () => { }) it('handles css objects', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 8px; @@ -74,13 +62,11 @@ describe('#jsx', () => { }) it('handles array of css objects', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container.firstChild).toHaveStyle(` margin: 8px; @@ -89,28 +75,24 @@ describe('#jsx', () => { }) it('does not render children', () => { - const { container } = render( - -
- , + const { container } = renderWithTheme( +
) expect(container).toHaveTextContent('') }) it('renders a single child', () => { - const { container } = render( - -
-

A testing paragraph

-
-
, + const { container } = renderWithTheme( +
+

A testing paragraph

+
) expect(container.querySelector('#test-p')).toHaveTextContent( @@ -119,17 +101,15 @@ describe('#jsx', () => { }) it('renders multiple children', () => { - const { container } = render( - -
-

First testing paragraph

+ const { container } = renderWithTheme( +
+

First testing paragraph

-

Second testing paragraph

-
- , +

Second testing paragraph

+
) expect(container.querySelectorAll('.test-p')).toHaveLength(2) diff --git a/packages/emotion/src/styled.test.tsx b/packages/emotion/src/styled.test.tsx index 515ec2ef..42a55980 100644 --- a/packages/emotion/src/styled.test.tsx +++ b/packages/emotion/src/styled.test.tsx @@ -1,22 +1,16 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' import { render, cleanup } from '@testing-library/react' -import { ThemeProvider } from '@emotion/react' import styled, { css, keyframes } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#styled', () => { it('supports basic tags', () => { const Dummy = styled.div`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') }) it('passes options through', () => { @@ -39,11 +33,7 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { padding: 1; margin-top: 2px; ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle(` margin: 2px 8px 8px 8px; padding: 4px; @@ -56,7 +46,7 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { } // @ts-ignore const Dummy = styled[key]` - color: red; + color: pink; ${ // @ts-ignore (p) => css` @@ -64,13 +54,9 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { ` } ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle(` - color: red; + color: pink; margin: 8px; `) }) @@ -98,38 +84,20 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { }) it('reads value from the theme', () => { - const theme = { - colors: { - primary: 'pink', - }, - } // @ts-ignore const Dummy = styled[key]` color: primary; ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('color: pink;') }) it('handles negative values', () => { - const theme = { - space: { - md: 10, - }, - } // @ts-ignore const Dummy = styled[key]` margin: -md; ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: -10px;') }) @@ -138,11 +106,7 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { const Dummy = styled[key]({ margin: '2', }) - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 8px;') }) @@ -151,11 +115,7 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { const Dummy = styled[key](() => ({ margin: '2', })) - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: 8px;') }) @@ -193,23 +153,15 @@ describe.each([['div'], ['box']])('#styled.%s', (key) => { describe('#styled.xxxBox', () => { it('supports box tags', () => { const Dummy = styled.box`` - const { container } = render( - - - , - ) - expect(container.firstChild!.nodeName).toBe('DIV') + const { container } = renderWithTheme() + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 4px;') }) it('supports xxxBox tags', () => { const Dummy = styled.headerBox`` - const { container } = render( - - - , - ) - expect(container.firstChild!.nodeName).toBe('HEADER') + const { container } = renderWithTheme() + expect(container.firstChild?.nodeName).toBe('HEADER') expect(container.firstChild).toHaveStyle('margin: 4px;') }) @@ -217,24 +169,16 @@ describe('#styled.xxxBox', () => { const Dummy = styled.box` margin: 2px; ` - const { container } = render( - - - , - ) - expect(container.firstChild!.nodeName).toBe('DIV') + const { container } = renderWithTheme() + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 4px;') expect(container.firstChild).not.toHaveStyle('margin: 2px;') }) it("doesn't forward attributes", () => { const Dummy = styled.box`` - const { container } = render( - - - , - ) - expect(container.firstChild!.nodeName).toBe('DIV') + const { container } = renderWithTheme() + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 4px;') expect(container.firstChild).not.toHaveAttribute('margin') }) @@ -244,7 +188,7 @@ describe('#styled.xxxBox', () => { // This is not supported by Emotion // @ts-expect-error const { container } = render() - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle('margin: 4px;') expect(container.firstChild).not.toHaveAttribute('margin') }) diff --git a/packages/emotion/src/theme.test.tsx b/packages/emotion/src/theme.test.tsx index b08ae3bf..53a041d9 100644 --- a/packages/emotion/src/theme.test.tsx +++ b/packages/emotion/src/theme.test.tsx @@ -1,14 +1,96 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' +import { render, cleanup, RenderOptions, RenderResult } from '@testing-library/react' import { ThemeProvider } from '@emotion/react' import { useTheme, useFontSize } from '.' +// import original module declarations +import '@xstyled/system' +import '@emotion/react' +import { + defaultTheme as xstyledDefaultTheme, + DefaultTheme as XStyledDefaultTheme, + th +} from '@xstyled/system' + +import { + ITheme, +} from '@xstyled/emotion' + +interface AppTheme extends ITheme, XStyledDefaultTheme { + fontSizes: XStyledDefaultTheme['fontSizes'] & { + md: string + } + colors: XStyledDefaultTheme['colors'] & { + primary: string + danger: any + text: any + red: string + modes: { + [key: string]: Partial + } + } + space: XStyledDefaultTheme['space'] & { + md: number + } +} + +// and extend them! +declare module '@xstyled/system' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface Theme extends AppTheme {} +} + +declare module '@emotion/react' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface Theme extends AppTheme {} +} + +const defaultTheme: XStyledDefaultTheme = xstyledDefaultTheme + +export const theme: AppTheme = { + ...defaultTheme, + + defaultColorModeName: 'dark', + colors: { + ...defaultTheme.colors, + primary: 'pink', + black: '#000', + white: '#fff', + red: '#ff0000', + danger: th.color('red'), + text: th.color('black'), + modes: { + dark: { + red: '#ff4400', + text: th.color('white'), + }, + }, + }, + space: { + ...defaultTheme.space, + md: 10, + 1: '4px', + 2: '8px' + }, + fontSizes: { + ...defaultTheme.fontSizes, + md: '20px', + }, +} as const + +export const renderWithTheme = ( + ui: React.ReactElement, + options?: Omit +): RenderResult => render( + {ui}, + options +) + afterEach(cleanup) describe('#useTheme', () => { it('returns theme', () => { - const theme = { foo: 'bar' } const spy = jest.fn() function ThemeLogger() { const theme = useTheme() @@ -17,10 +99,8 @@ describe('#useTheme', () => { }, [theme]) return null } - render( - - - , + renderWithTheme( + ) expect(spy).toHaveBeenCalledWith(theme) }) @@ -28,7 +108,6 @@ describe('#useTheme', () => { describe('#useFontSize', () => { it('gets value from theme', () => { - const theme = { fontSizes: { md: '20px' } } const spy = jest.fn() function Logger() { const fontSize = useFontSize('md') @@ -37,10 +116,8 @@ describe('#useFontSize', () => { }, [fontSize]) return null } - render( - - - , + renderWithTheme( + ) expect(spy).toHaveBeenCalledWith('20px') }) diff --git a/packages/emotion/src/x.test.tsx b/packages/emotion/src/x.test.tsx index 6a148d29..edae156c 100644 --- a/packages/emotion/src/x.test.tsx +++ b/packages/emotion/src/x.test.tsx @@ -1,17 +1,11 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' import { render, cleanup } from '@testing-library/react' -import { ThemeProvider } from '@emotion/react' import { x } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#x', () => { it('creates system based components', () => { const { container } = render() @@ -25,7 +19,7 @@ describe('#x', () => { // "as" is not supported with emotion // @ts-expect-error const { container } = render() - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 2px; padding: 1px; @@ -38,7 +32,7 @@ describe('#x', () => { Hello , ) - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 2px; padding: 1px; @@ -46,14 +40,12 @@ describe('#x', () => { }) it('uses theme', () => { - const { container } = render( - - - Hello - - , + const { container } = renderWithTheme( + + Hello + ) - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 8px; padding: 4px; @@ -62,7 +54,7 @@ describe('#x', () => { it('does not forward props', () => { const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('display: flex;') expect(container.firstChild).not.toHaveAttribute('display') expect(container.firstChild).toHaveAttribute('data-foo') diff --git a/packages/styled-components/src/colorModes.test.tsx b/packages/styled-components/src/colorModes.test.tsx index 1e78f859..5eb70523 100644 --- a/packages/styled-components/src/colorModes.test.tsx +++ b/packages/styled-components/src/colorModes.test.tsx @@ -1,37 +1,18 @@ /* eslint-env browser */ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { th } from '@xstyled/system' -import { x, ThemeProvider, ColorModeProvider } from '.' +import { cleanup } from '@testing-library/react' +import { x, ColorModeProvider } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) describe('colorModes', () => { it('supports color modes', () => { - const theme = { - defaultColorModeName: 'dark', - colors: { - black: '#000', - white: '#fff', - red: '#ff0000', - danger: th.color('red'), - text: th.color('black'), - modes: { - dark: { - red: '#ff4400', - text: th.color('white'), - }, - }, - }, - } - - render( - - - Hello - - , + renderWithTheme( + + Hello + ) expect(document.body).toHaveClass('xstyled-color-mode-dark') }) diff --git a/packages/styled-components/src/createGlobalStyle.test.tsx b/packages/styled-components/src/createGlobalStyle.test.tsx index d886f625..9853da4e 100644 --- a/packages/styled-components/src/createGlobalStyle.test.tsx +++ b/packages/styled-components/src/createGlobalStyle.test.tsx @@ -1,16 +1,11 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { createGlobalStyle, css, ThemeProvider } from '.' +import { cleanup } from '@testing-library/react' +import { createGlobalStyle, css } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#createGlobalStyle', () => { it('injects global styles', () => { const GlobalStyle = createGlobalStyle` @@ -18,12 +13,10 @@ describe('#createGlobalStyle', () => { margin: 2; } ` - const { container } = render( + const { container } = renderWithTheme( <> - - -
- + +
, ) expect(container.firstChild).toHaveStyle(` @@ -40,12 +33,10 @@ describe('#createGlobalStyle', () => { const GlobalStyle = createGlobalStyle` ${style} ` - const { container } = render( + const { container } = renderWithTheme( <> - - -
- + +
, ) expect(container.firstChild).toHaveStyle(` diff --git a/packages/styled-components/src/css.test.tsx b/packages/styled-components/src/css.test.tsx index 9c257e27..b56cd2c0 100644 --- a/packages/styled-components/src/css.test.tsx +++ b/packages/styled-components/src/css.test.tsx @@ -1,17 +1,12 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { css, ThemeProvider } from '.' +import { cleanup } from '@testing-library/react' +import { css } from '.' import { scStyled as styled } from './scStyled' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#css', () => { it('transforms rules', () => { const Dummy = styled.div` @@ -21,10 +16,8 @@ describe('#css', () => { margin-top: 2px; `} ` - const { container } = render( - + const { container } = renderWithTheme( - , ) expect(container.firstChild).toHaveStyle(` margin: 2px 8px 8px 8px; @@ -38,10 +31,8 @@ describe('#css', () => { margin: 1 2; `} ` - const { container } = render( - + const { container } = renderWithTheme( - , ) expect(container.firstChild).toHaveStyle('margin: 4px 8px;') }) diff --git a/packages/styled-components/src/styled.test.tsx b/packages/styled-components/src/styled.test.tsx index af4eedc9..da6e8ca1 100644 --- a/packages/styled-components/src/styled.test.tsx +++ b/packages/styled-components/src/styled.test.tsx @@ -1,8 +1,9 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' -import { ThemeProvider, keyframes } from 'styled-components' +import { render, cleanup, } from '@testing-library/react' +import { keyframes } from 'styled-components' import styled, { css, system } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) @@ -50,36 +51,18 @@ describe('#styled', () => { }) it('reads value from the theme', () => { - const theme = { - colors: { - primary: 'pink', - }, - } const Dummy = styled.div` color: primary; ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('color: pink;') }) it('handles negative values', () => { - const theme = { - space: { - md: 10, - }, - } const Dummy = styled.div` margin: -md; ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle('margin: -10px;') }) @@ -131,19 +114,10 @@ describe('#styled', () => { }) it('works with system.apply', () => { - const theme = { - colors: { - primary: 'pink', - }, - } const Dummy = styled.div` ${system.apply({ fontSize: 2, bg: 'primary' })} ` - const { container } = render( - - - , - ) + const { container } = renderWithTheme() expect(container.firstChild).toHaveStyle(` font-size: 2px; background-color: pink; @@ -155,7 +129,7 @@ describe('#styled.xxx', () => { it('supports basic tags', () => { const Dummy = styled.div`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') }) }) @@ -163,14 +137,14 @@ describe('#styled.xxxBox', () => { it('supports box tags', () => { const Dummy = styled.box`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 1px;') }) it('supports xxxBox tags', () => { const Dummy = styled.aBox`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle('margin: 1px;') }) @@ -179,7 +153,7 @@ describe('#styled.xxxBox', () => { margin: 2px; ` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 1px;') expect(container.firstChild).not.toHaveStyle('margin: 2px;') }) @@ -187,7 +161,7 @@ describe('#styled.xxxBox', () => { it("doesn't forward attributes", () => { const Dummy = styled.box`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('margin: 1px;') expect(container.firstChild).not.toHaveAttribute('margin') }) @@ -195,7 +169,7 @@ describe('#styled.xxxBox', () => { it('supports as prop', () => { const Dummy = styled.divBox`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('HEADER') + expect(container.firstChild?.nodeName).toBe('HEADER') expect(container.firstChild).toHaveStyle('margin: 1px;') expect(container.firstChild).not.toHaveAttribute('margin') }) @@ -203,7 +177,7 @@ describe('#styled.xxxBox', () => { it('does not forward props', () => { const Dummy = styled.divBox`` const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('display: flex;') expect(container.firstChild).not.toHaveAttribute('display') expect(container.firstChild).toHaveAttribute('data-foo') diff --git a/packages/styled-components/src/theme.test.tsx b/packages/styled-components/src/theme.test.tsx index a9d241bb..aaa2f0d7 100644 --- a/packages/styled-components/src/theme.test.tsx +++ b/packages/styled-components/src/theme.test.tsx @@ -1,14 +1,95 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' -import { render, cleanup } from '@testing-library/react' +import { render, cleanup, RenderOptions, RenderResult } from '@testing-library/react' import { ThemeProvider } from 'styled-components' import { useTheme, useFontSize } from '.' +// import original module declarations +import 'styled-components' +import '@xstyled/system' +import { + defaultTheme as xstyledDefaultTheme, + DefaultTheme as XStyledDefaultTheme, + th +} from '@xstyled/system' +import { + ITheme, +} from '@xstyled/styled-components' + +interface AppTheme extends ITheme, XStyledDefaultTheme { + fontSizes: XStyledDefaultTheme['fontSizes'] & { + md: string + } + colors: XStyledDefaultTheme['colors'] & { + primary: string + danger: any + text: any + red: string + modes: { + [key: string]: Partial + } + } + space: XStyledDefaultTheme['space'] & { + md: number + } +} + +// and extend them! +declare module '@xstyled/system' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface Theme extends AppTheme {} +} +declare module 'styled-components' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface DefaultTheme extends AppTheme {} +} + +const defaultTheme: XStyledDefaultTheme = xstyledDefaultTheme + +const theme: AppTheme = { + ...defaultTheme, + + defaultColorModeName: 'dark', + colors: { + ...defaultTheme.colors, + primary: 'pink', + black: '#000', + white: '#fff', + red: '#ff0000', + danger: th.color('red'), + text: th.color('black'), + modes: { + dark: { + red: '#ff4400', + text: th.color('white'), + }, + }, + }, + space: { + ...defaultTheme.space, + md: 10, + 1: '4px', + 2: '8px' + }, + fontSizes: { + ...defaultTheme.fontSizes, + md: '20px', + }, +} as const + + +export const renderWithTheme = ( + ui: React.ReactElement, + options?: Omit +): RenderResult => render( + {ui}, + options +) + afterEach(cleanup) describe('#useTheme', () => { it('returns theme', () => { - const theme = { foo: 'bar' } const spy = jest.fn() function ThemeLogger() { const theme = useTheme() @@ -17,18 +98,13 @@ describe('#useTheme', () => { }, [theme]) return null } - render( - - - , - ) + renderWithTheme() expect(spy).toHaveBeenCalledWith(theme) }) }) describe('#useFontSize', () => { it('gets value from theme', () => { - const theme = { fontSizes: { md: '20px' } } const spy = jest.fn() function Logger() { const fontSize = useFontSize('md') @@ -37,11 +113,7 @@ describe('#useFontSize', () => { }, [fontSize]) return null } - render( - - - , - ) + renderWithTheme() expect(spy).toHaveBeenCalledWith('20px') }) }) diff --git a/packages/styled-components/src/x.test.tsx b/packages/styled-components/src/x.test.tsx index f8bce9a1..b90f8f7b 100644 --- a/packages/styled-components/src/x.test.tsx +++ b/packages/styled-components/src/x.test.tsx @@ -1,17 +1,11 @@ import * as React from 'react' import '@testing-library/jest-dom/extend-expect' import { render, cleanup } from '@testing-library/react' -import { ThemeProvider } from 'styled-components' import { x } from '.' +import { renderWithTheme } from './theme.test' afterEach(cleanup) -const SpaceTheme = ({ children }: { children: React.ReactNode }) => { - return ( - {children} - ) -} - describe('#x', () => { it('creates system based components', () => { const { container } = render() @@ -23,7 +17,7 @@ describe('#x', () => { it('supports "as" prop', () => { const { container } = render() - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 2px; padding: 1px; @@ -36,7 +30,7 @@ describe('#x', () => { Hello , ) - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 2px; padding: 1px; @@ -44,14 +38,12 @@ describe('#x', () => { }) it('uses theme', () => { - const { container } = render( - - - Hello - - , + const { container } = renderWithTheme( + + Hello + ) - expect(container.firstChild!.nodeName).toBe('A') + expect(container.firstChild?.nodeName).toBe('A') expect(container.firstChild).toHaveStyle(` margin: 8px; padding: 4px; @@ -60,7 +52,7 @@ describe('#x', () => { it('does not forward props', () => { const { container } = render() - expect(container.firstChild!.nodeName).toBe('DIV') + expect(container.firstChild?.nodeName).toBe('DIV') expect(container.firstChild).toHaveStyle('display: flex;') expect(container.firstChild).not.toHaveAttribute('display') expect(container.firstChild).toHaveAttribute('data-foo') diff --git a/packages/system/src/styles/flexbox-grids.test.ts b/packages/system/src/styles/flexbox-grids.test.ts index 190e091a..fed896ab 100644 --- a/packages/system/src/styles/flexbox-grids.test.ts +++ b/packages/system/src/styles/flexbox-grids.test.ts @@ -14,6 +14,8 @@ const theme = { describe('#flexboxGrids', () => { it('supports row', () => { + expect(flexboxGrids({ row: false })).toEqual({}) + expect(flexboxGrids({ row: true })).toEqual({ boxSizing: 'border-box', flexGrow: 1, @@ -48,6 +50,8 @@ describe('#flexboxGrids', () => { flex: '0 0 33.3333%', }) + expect(flexboxGrids({ col: false })).toEqual({}) + expect(flexboxGrids({ col: true })).toEqual({ boxSizing: 'border-box', flexBasis: 0, diff --git a/packages/system/src/styles/flexbox-grids.ts b/packages/system/src/styles/flexbox-grids.ts index 8c342390..16a43b27 100644 --- a/packages/system/src/styles/flexbox-grids.ts +++ b/packages/system/src/styles/flexbox-grids.ts @@ -4,16 +4,16 @@ import { style, createStyleGenerator, reduceVariants, compose } from '../style' import { getPercent } from './units' export interface RowProps { - row?: SystemProp + row?: SystemProp } export const row = style({ prop: 'row', - css: () => ({ + css: value => value ? { boxSizing: 'border-box', flexGrow: 1, flexWrap: 'wrap', display: 'flex', - }), + } : {}, }) const getColStyle = ( @@ -47,7 +47,7 @@ const getColStyle = ( } export interface ColProps { - col?: SystemProp + col?: SystemProp } export const col = createStyleGenerator({ getStyle: (props) => { @@ -59,6 +59,10 @@ export const col = createStyleGenerator({ maxWidth: '100%', } + if (value === false) { + return null + } + if (obj(value)) { const breakpointsStyle = reduceVariants( props, diff --git a/packages/system/src/styles/index.test.ts b/packages/system/src/styles/index.test.ts index 5e6cdac6..d3d25518 100644 --- a/packages/system/src/styles/index.test.ts +++ b/packages/system/src/styles/index.test.ts @@ -15,7 +15,7 @@ describe('#system', () => { spaceY: { _: 3, sm: 0 }, spaceX: { sm: 4 }, }) - const keys = Object.keys(res) + const keys = Object.keys(res ?? {}) expect(keys).toEqual([ 'display', '& > :not([hidden]) ~ :not([hidden])', diff --git a/packages/system/src/types.ts b/packages/system/src/types.ts index 4a6eba54..18b9da31 100644 --- a/packages/system/src/types.ts +++ b/packages/system/src/types.ts @@ -81,6 +81,9 @@ export type ThemeProp = { export type SystemProp = | TType | ThemeProp + | string + | number + | false export type CSSOption = string | string[] | Mixin @@ -129,7 +132,7 @@ export type ThemeNamespaceValue< > = SynthesizedPath export interface ThemeGetter { - (value: T, defaultValue?: CSSScalar): (props: Props) => CSSScalar + (value: T | string | number | boolean, defaultValue?: CSSScalar): (props: Props) => CSSScalar meta: { name?: string transform?: TransformValue diff --git a/website/pages/docs/core-concepts/typescript.mdx b/website/pages/docs/core-concepts/typescript.mdx index 76e26ad5..129609bd 100644 --- a/website/pages/docs/core-concepts/typescript.mdx +++ b/website/pages/docs/core-concepts/typescript.mdx @@ -65,9 +65,7 @@ declare module '@xstyled/system' { export interface Theme extends AppTheme {} } declare module '@emotion/react' { - export interface Theme extends XStyledDefaultTheme { - /* Customize your theme */ - } + export interface Theme extends AppTheme {} } ```