Skip to content

Commit

Permalink
breaking feat: styled-components v6
Browse files Browse the repository at this point in the history
  • Loading branch information
quantizor committed May 8, 2024
1 parent d213d97 commit 0c437fd
Show file tree
Hide file tree
Showing 26 changed files with 173 additions and 129 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion benchmarks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@xstyled/emotion": "^3.8.0",
"@xstyled/styled-components": "^3.8.0",
"emotion-theming": "^11.0.0",
"styled-components": "^5.3.6",
"styled-components": "^6.1.9",
"styled-system": "^5.1.5"
}
}
9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/react": "^18.0.21",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0",
"babel-jest": "^29.1.2",
Expand All @@ -49,12 +48,13 @@
"rollup": "^2.79.1",
"rollup-plugin-dts": "^4.2.2",
"rollup-plugin-esbuild": "^4.10.1",
"styled-components": "^5.3.6",
"styled-components": "^6.1.9",
"typescript": "^4.8.4"
},
"resolutions": {
"smooth-doc/styled-components": "^5.2.3",
"smooth-doc/gatsby-plugin-robots-txt": "1.5.6"
"smooth-doc/gatsby-plugin-robots-txt": "1.5.6",
"styled-components": "test"
},
"bundlewatch": {
"files": [
Expand All @@ -80,8 +80,5 @@
}
]
},
"overrides": {
"babel-plugin-styled-components": "2.0.2"
},
"packageManager": "[email protected]"
}
3 changes: 2 additions & 1 deletion packages/styled-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"styled-components": "^4.0.0 || ^5.0.0"
"styled-components": "^6.0.0"
},
"dependencies": {
"@emotion/is-prop-valid": "^1.2.2",
"@xstyled/core": "^3.8.0",
"@xstyled/system": "^3.8.0",
"@xstyled/util": "^3.7.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/styled-components/src/breakpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
useThemeDown,
} from '@xstyled/core'
import { Screens } from '@xstyled/system'
import { useTheme } from './theme'
import { useTheme } from 'styled-components'

export { useViewportWidth } from '@xstyled/core'

Expand Down
14 changes: 6 additions & 8 deletions packages/styled-components/src/createCreateGlobalStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ export type XCreateGlobalStyle = typeof scCreateGlobalStyle
export const createCreateGlobalStyle = <TGen extends StyleGenerator>(
generator: TGen,
): XCreateGlobalStyle => {
const css = createCssFunction(generator)
return ((
...args: Parameters<XCreateGlobalStyle>
): ReturnType<XCreateGlobalStyle> =>
scCreateGlobalStyle([
// @ts-ignore
css(...args),
])) as XCreateGlobalStyle
const css = createCssFunction<TGen>(generator)
return <Props extends object>(
...args: Parameters<typeof scCreateGlobalStyle<Props>>
) =>
// @ts-expect-error
scCreateGlobalStyle<Props>([css<Props>(...args)])
}
21 changes: 9 additions & 12 deletions packages/styled-components/src/createCssFunction.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
/* eslint-disable no-continue, no-loop-func, no-cond-assign */
import {
css as scCss,
FlattenSimpleInterpolation,
ThemedCssFunction,
} from 'styled-components'
import { StyleGenerator, Theme } from '@xstyled/system'
import { flattenStrings } from '@xstyled/util'
import { createTransform } from '@xstyled/core'
import { StyleGenerator } from '@xstyled/system'
import { flattenStrings } from '@xstyled/util'
import { css as scCss } from 'styled-components'

export type XCSSFunction = ThemedCssFunction<Theme>
export type XCSSFunction = typeof scCss

export const createCssFunction = <TGen extends StyleGenerator>(
generator: TGen,
): XCSSFunction => {
const transform = createTransform(generator)
return ((...args: Parameters<XCSSFunction>) => {
const scCssArgs = scCss(...args)

return <Props extends object>(...args: Parameters<XCSSFunction>) => {
const scCssArgs = scCss<Props>(...args)
const flattenedArgs = flattenStrings(scCssArgs as any[])
return flattenedArgs.map(transform) as FlattenSimpleInterpolation
}) as XCSSFunction
return flattenedArgs.map(transform) as ReturnType<typeof scCss<Props>>
}
}
2 changes: 1 addition & 1 deletion packages/styled-components/src/createGlobalStyle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('#createGlobalStyle', () => {
const GlobalStyle = createGlobalStyle`
.margin {
margin: 2;
}
}
`
const { container } = render(
<>
Expand Down
70 changes: 34 additions & 36 deletions packages/styled-components/src/createStyled.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,51 @@
/* eslint-disable no-continue, no-loop-func, no-cond-assign */
import type { ElementType } from 'react'
import isPropValid from '@emotion/is-prop-valid'
import { BoxElements } from '@xstyled/core'
import { StyleGenerator, StyleGeneratorProps } from '@xstyled/system'
import { string } from '@xstyled/util'
import { StyleGenerator, StyleGeneratorProps, Theme } from '@xstyled/system'
import {
StyledConfig,
ThemedBaseStyledInterface,
ThemedStyledFunction,
LibraryStyled,
ShouldForwardProp,
Styled,
StyledInstance,
StyledOptions,
WebTarget,
} from 'styled-components'
import { XCSSFunction, createCssFunction } from './createCssFunction'
import { scStyled } from './scStyled'
import { createCssFunction, XCSSFunction } from './createCssFunction'

const getCreateStyle = (
baseCreateStyle: ThemedStyledFunction<any, any>,
const getCreateStyle = <TGen extends StyleGenerator>(
baseCreateStyle: StyledInstance<'web', any, any>,
css: XCSSFunction,
generator?: StyleGenerator,
) => {
generator?: TGen,
): ReturnType<LibraryStyled<StyleGeneratorProps<TGen>>> => {
const createStyle = (...args: Parameters<typeof css>) =>
// @ts-ignore
baseCreateStyle`${css(...args)}${generator}`
createStyle.attrs = (attrs: Parameters<typeof baseCreateStyle.attrs>[0]) =>
getCreateStyle(baseCreateStyle.attrs(attrs), css, generator)
createStyle.withConfig = (config: StyledConfig<any>) =>
getCreateStyle(baseCreateStyle.withConfig(config), css, generator)
getCreateStyle<TGen>(baseCreateStyle.attrs(attrs), css, generator)
createStyle.withConfig = (config: StyledOptions<'web', any>) =>
getCreateStyle<TGen>(baseCreateStyle.withConfig(config), css, generator)
// @ts-expect-error
return createStyle
}

type BoxStyledTags<TProps extends object> = {
[Key in keyof BoxElements]: ThemedStyledFunction<
[Key in keyof BoxElements]: StyledInstance<
'web',
BoxElements[Key],
Theme,
TProps
Omit<JSX.IntrinsicElements[BoxElements[Key]], keyof TProps> & TProps
>
}

export interface XStyled<TGen extends StyleGenerator>
extends ThemedBaseStyledInterface<Theme>,
extends Styled,
BoxStyledTags<StyleGeneratorProps<TGen>> {}

const createShouldForwardProp = (
generator: StyleGenerator,
): ((
prop: string | number | symbol,
defaultValidatorFn: (prop: string | number | symbol) => boolean,
elementToBeCreated?: ElementType,
) => boolean) => {
): ShouldForwardProp<'web'> => {
const propSet = new Set<string>(generator.meta.props)
return (
prop: string | number | symbol,
defaultValidatorFn: (prop: string | number | symbol) => boolean,
elementToBeCreated?: ElementType,
) => {
return (prop: string, elementToBeCreated?: WebTarget) => {
if (string(prop) && propSet.has(prop)) {
return false
}
Expand All @@ -61,7 +56,7 @@ const createShouldForwardProp = (
// This means that HTML elements could get unwanted props, but ultimately
// this is a bug in the caller, because why are they passing unwanted
// props?
return defaultValidatorFn(prop)
return isPropValid(prop)
}
return true
}
Expand All @@ -71,33 +66,36 @@ export const createBaseStyled = <TGen extends StyleGenerator>(
css: XCSSFunction,
generator?: TGen,
): XStyled<TGen> => {
const config = generator
const config: StyledOptions<'web', object> = generator
? {
shouldForwardProp: createShouldForwardProp(generator),
}
: {}
return ((component: Parameters<typeof scStyled>[0]) => {
const baseStyled = scStyled(component)
return getCreateStyle(
return getCreateStyle<TGen>(
config ? baseStyled.withConfig(config) : baseStyled,
css,
generator,
)
}) as XStyled<TGen>
}

type JSXElementKeys = keyof JSX.IntrinsicElements

export const createStyled = <TGen extends StyleGenerator>(
generator: TGen,
): XStyled<TGen> => {
const css = createCssFunction(generator)
const styled = createBaseStyled(css)
const xstyled = createBaseStyled(css, generator)
const styled = createBaseStyled<TGen>(css)
const xstyled = createBaseStyled<TGen>(css, generator)
styled.box = xstyled('div')
Object.keys(scStyled).forEach((key) => {
// @ts-ignore
;(Object.keys(scStyled) as JSXElementKeys[]).forEach((key) => {
// @ts-expect-error
styled[key] = styled(key)
// @ts-ignore
// @ts-expect-error
styled[`${key}Box`] = xstyled(key)
})

return styled
}
20 changes: 5 additions & 15 deletions packages/styled-components/src/createX.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,22 @@
/* eslint-disable no-continue, no-loop-func, no-cond-assign */
import { StyledComponent, DefaultTheme } from 'styled-components'
import { scStyled } from './scStyled'
import { StyleGenerator, StyleGeneratorProps } from '@xstyled/system'
import { createBaseStyled } from './createStyled'
import { StyledInstance } from 'styled-components'
import { createCssFunction } from './createCssFunction'
import { createBaseStyled } from './createStyled'
import { scStyled } from './scStyled'

type JSXElementKeys = keyof JSX.IntrinsicElements

type SafeIntrinsicElement<T extends keyof JSX.IntrinsicElements> = (
props: Omit<JSX.IntrinsicElements[T], 'color'>,
) => React.ReactElement<any, T>

export type X<TGen extends StyleGenerator> = {
[Key in JSXElementKeys]: StyledComponent<
SafeIntrinsicElement<Key>,
DefaultTheme,
StyleGeneratorProps<TGen>,
'color'
>
[Key in JSXElementKeys]: StyledInstance<'web', Key, StyleGeneratorProps<TGen>>
}

export const createX = <TGen extends StyleGenerator>(
generator: TGen,
): X<TGen> => {
const xstyled = createBaseStyled(createCssFunction(generator), generator)
const x = {} as X<TGen>
Object.keys(scStyled).forEach((tag) => {
// @ts-ignore
;(Object.keys(scStyled) as JSXElementKeys[]).forEach((tag) => {
x[tag] = xstyled(tag)``
})
return x
Expand Down
6 changes: 3 additions & 3 deletions packages/styled-components/src/scStyled.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components'
import styled, { Styled } from 'styled-components'

// Provide interop since `styled-components` does not work out of the box with ESM
export const scStyled =
// @ts-ignore
typeof styled === 'function' ? styled : styled.default
// @ts-expect-error
(typeof styled === 'function' ? styled : styled.default) as Styled
6 changes: 2 additions & 4 deletions packages/styled-components/src/styled.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ describe('#styled', () => {
})

it('works with render props', () => {
const Foo = ({
children,
}: {
const Foo: React.FC<{
children: ({ content }: { content: string }) => React.ReactNode
}) => <div>{children({ content: 'Hello World' })}</div>
}> = ({ children }) => <div>{children({ content: 'Hello World' })}</div>

const StyledFoo = styled(Foo)``

Expand Down
7 changes: 2 additions & 5 deletions packages/styled-components/src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { useContext, ContextType } from 'react'
import { ThemeContext } from 'styled-components'
import { createUseGetter } from '@xstyled/core'
import { th } from '@xstyled/system'
import { useTheme } from 'styled-components'

export const useTheme = (): ContextType<typeof ThemeContext> => {
return useContext(ThemeContext)
}
export { useTheme }

export const useTh = createUseGetter(th, useTheme)

Expand Down
3 changes: 3 additions & 0 deletions packages/system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@
"dependencies": {
"@xstyled/util": "^3.7.0",
"csstype": "^3.1.1"
},
"devDependencies": {
"@emotion/is-prop-valid": "^1.2.2"
}
}
7 changes: 4 additions & 3 deletions packages/system/tests/styled-components/styles.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react'
import 'jest-styled-components'
import '@testing-library/jest-dom/extend-expect'
import isPropValid from '@emotion/is-prop-valid'
import { render, cleanup } from '@testing-library/react'
import styled from 'styled-components'
import * as styles from '../../src'
Expand Down Expand Up @@ -588,10 +589,10 @@ describe('styles', () => {
},
styleRule: 'box-shadow',
expectations: [
['red', 'var(--x-ring-shadow,0 0 #0000),var(--x-shadow)'],
['red', 'var(--x-ring-shadow, 0 0 #0000),var(--x-shadow)'],
[
'12px 12px 2px 1px rgba(0, 0, 255, .2)',
'var(--x-ring-shadow,0 0 #0000),var(--x-shadow)',
'var(--x-ring-shadow, 0 0 #0000),var(--x-shadow)',
],
],
},
Expand Down Expand Up @@ -622,7 +623,7 @@ describe('styles', () => {
},
],
])('#%s', (name, config) => {
const Dummy = styled.div`
const Dummy = styled.div.withConfig({ shouldForwardProp: isPropValid })`
${styles[(config as any).utility || name]};
`

Expand Down
Loading

0 comments on commit 0c437fd

Please sign in to comment.