Skip to content

Commit

Permalink
feat!(styled-components): adopt styled-components v6
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Minimum version of styled-components is now 6.1.11. See
the [migration guide](https://styled-components.com/docs/faqs#what-do-i-need-to-do-to-migrate-to-v6) for more information.
  • Loading branch information
quantizor committed May 9, 2024
1 parent 53007c2 commit 86d9a88
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 102 deletions.
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.1.11"
},
"dependencies": {
"@emotion/is-prop-valid": "^1.2.2",
"@xstyled/core": "^3.8.1",
"@xstyled/system": "^3.8.1",
"@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
16 changes: 8 additions & 8 deletions packages/styled-components/src/create.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { StyleGenerator } from '@xstyled/system'
import { createCssFunction, XCSSFunction } from './createCssFunction'
import { createX, X } from './createX'
import { createStyled, XStyled } from './createStyled'
import {
createCreateGlobalStyle,
XCreateGlobalStyle,
createCreateGlobalStyle,
} from './createCreateGlobalStyle'
import { XCSSFunction, createCssFunction } from './createCssFunction'
import { XStyled, createStyled } from './createStyled'
import { X, createX } from './createX'

export interface XStyledSet<TGen extends StyleGenerator> {
css: XCSSFunction
Expand All @@ -18,9 +18,9 @@ export const createCss = <TGen extends StyleGenerator>(
generator: TGen,
): XStyledSet<TGen> => {
return {
css: createCssFunction(generator),
x: createX(generator),
styled: createStyled(generator),
createGlobalStyle: createCreateGlobalStyle(generator),
css: createCssFunction<TGen>(generator),
x: createX<TGen>(generator),
styled: createStyled<TGen>(generator),
createGlobalStyle: createCreateGlobalStyle<TGen>(generator),
}
}
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
75 changes: 37 additions & 38 deletions packages/styled-components/src/createStyled.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,52 @@
/* 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,
FastOmit,
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
FastOmit<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 +57,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 +67,36 @@ export const createBaseStyled = <TGen extends StyleGenerator>(
css: XCSSFunction,
generator?: TGen,
): XStyled<TGen> => {
const config = generator
const config: StyledOptions<'web', any> = generator
? {
shouldForwardProp: createShouldForwardProp(generator),
}
: {}
return ((component: Parameters<typeof scStyled>[0]) => {
return (<Target extends WebTarget>(component: Target) => {
const baseStyled = scStyled(component)
return getCreateStyle(
return getCreateStyle<TGen>(
config ? baseStyled.withConfig(config) : baseStyled,
css,
generator,
)
}) as XStyled<TGen>
}

type JSXElementKeys = BoxElements[keyof BoxElements]

export const createStyled = <TGen extends StyleGenerator>(
generator: TGen,
): XStyled<TGen> => {
const css = createCssFunction(generator)
const styled = createBaseStyled(css)
const xstyled = createBaseStyled(css, generator)
const css = createCssFunction<TGen>(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
}
34 changes: 17 additions & 17 deletions packages/styled-components/src/createX.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
/* 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 {
FastOmit,
SupportedHTMLElements,
IStyledComponent,
} from 'styled-components'
import { createCssFunction } from './createCssFunction'

type JSXElementKeys = keyof JSX.IntrinsicElements

type SafeIntrinsicElement<T extends keyof JSX.IntrinsicElements> = (
props: Omit<JSX.IntrinsicElements[T], 'color'>,
) => React.ReactElement<any, T>
import { createBaseStyled } from './createStyled'
import { scStyled } from './scStyled'

export type X<TGen extends StyleGenerator> = {
[Key in JSXElementKeys]: StyledComponent<
SafeIntrinsicElement<Key>,
DefaultTheme,
StyleGeneratorProps<TGen>,
'color'
[Key in SupportedHTMLElements]: IStyledComponent<
'web',
FastOmit<JSX.IntrinsicElements[Key], keyof StyleGeneratorProps<TGen>> &
StyleGeneratorProps<TGen>
>
}

export const createX = <TGen extends StyleGenerator>(
generator: TGen,
): X<TGen> => {
const xstyled = createBaseStyled(createCssFunction(generator), generator)
const xstyled = createBaseStyled<TGen>(
createCssFunction<TGen>(generator),
generator,
)
const x = {} as X<TGen>
Object.keys(scStyled).forEach((tag) => {
// @ts-ignore
x[tag] = xstyled(tag)``
// @ts-expect-error
x[tag] = xstyled(tag)({})
})
return x
}
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
8 changes: 4 additions & 4 deletions packages/styled-components/src/x.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('#x', () => {
const { container } = render(<x.div m={2} p={1} />)
expect(container.firstChild).toHaveStyle(`
margin: 2px;
padding: 1px;
padding: 1px;
`)
})

Expand All @@ -26,7 +26,7 @@ describe('#x', () => {
expect(container.firstChild!.nodeName).toBe('A')
expect(container.firstChild).toHaveStyle(`
margin: 2px;
padding: 1px;
padding: 1px;
`)
})

Expand All @@ -39,7 +39,7 @@ describe('#x', () => {
expect(container.firstChild!.nodeName).toBe('A')
expect(container.firstChild).toHaveStyle(`
margin: 2px;
padding: 1px;
padding: 1px;
`)
})

Expand All @@ -54,7 +54,7 @@ describe('#x', () => {
expect(container.firstChild!.nodeName).toBe('A')
expect(container.firstChild).toHaveStyle(`
margin: 8px;
padding: 4px;
padding: 4px;
`)
})

Expand Down

0 comments on commit 86d9a88

Please sign in to comment.