Skip to content

Commit fbbf91e

Browse files
committed
fix(types): fix types of CSS objects (#260)
1 parent 25f091d commit fbbf91e

File tree

18 files changed

+364
-367
lines changed

18 files changed

+364
-367
lines changed

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"plugin:react/recommended"
1313
],
1414
"rules": {
15-
"@typescript-eslint/ban-ts-comment": "warn",
15+
"@typescript-eslint/ban-ts-comment": "off",
16+
"@typescript-eslint/no-explicit-any": "off",
1617
"@typescript-eslint/no-empty-function": "warn",
1718
"@typescript-eslint/ban-types": "warn",
1819
"react/prop-types": "off"

packages/core/src/theme.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
import { useMemo } from 'react'
2-
import { ThemeGetter, ThemeGetterType, StyleScalarValue } from '@xstyled/system'
2+
import { ThemeGetter, ThemeGetterType, CSSScalar } from '@xstyled/system'
33

4-
export const createUseGetter = <T extends ThemeGetter>(
5-
getter: T,
6-
useTheme: () => object,
7-
) => (
8-
value: ThemeGetterType<T>,
9-
defaultValue?: StyleScalarValue,
10-
): StyleScalarValue => {
11-
const theme = useTheme()
12-
return useMemo(() => getter(value, defaultValue)({ theme }), [
13-
value,
14-
defaultValue,
15-
theme,
16-
])
17-
}
4+
export const createUseGetter =
5+
<T extends ThemeGetter>(getter: T, useTheme: () => object) =>
6+
(value: ThemeGetterType<T>, defaultValue?: CSSScalar): CSSScalar => {
7+
const theme = useTheme()
8+
return useMemo(
9+
() => getter(value, defaultValue)({ theme }),
10+
[value, defaultValue, theme],
11+
)
12+
}

packages/core/src/transform.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,6 @@ const MEDIA_PATT = (
3232

3333
const MATCH_REGEXP = new RegExp(`(?:${PROP_PATT}|${MEDIA_PATT})`, `g`)
3434

35-
export function transform(rawValue: any): any {
36-
if (typeof rawValue !== 'string') return rawValue
37-
let matches
38-
let lastIndex = 0
39-
const values = []
40-
while ((matches = MATCH_REGEXP.exec(rawValue))) {
41-
const [, prop, colon, value, imp, semi, media, query, brace] = matches
42-
if (media) {
43-
values.push(rawValue.slice(lastIndex, matches.index))
44-
values.push(media)
45-
mediaTransform(query).forEach((v) => values.push(v))
46-
values.push(brace)
47-
lastIndex = matches.index + matches[0].length
48-
} else {
49-
const getter = (propGetters as any)[prop]
50-
if (getter) {
51-
values.push(rawValue.slice(lastIndex, matches.index))
52-
values.push(
53-
(p: object) =>
54-
`${prop}${colon}${getter(value)(p)}${imp || ''}${semi}`,
55-
)
56-
lastIndex = matches.index + matches[0].length
57-
}
58-
}
59-
}
60-
values.push(rawValue.slice(lastIndex, rawValue.length))
61-
return values
62-
}
63-
6435
// media query prop/value pairs such as (min-width: 1024px)
6536
// prettier-ignore
6637
const QUERY_REGEXP = new RegExp(
@@ -72,7 +43,7 @@ const QUERY_REGEXP = new RegExp(
7243
`g`
7344
)
7445

75-
function mediaTransform(rawValue: string) {
46+
const mediaTransform = (rawValue: string) => {
7647
let matches
7748
let lastIndex = 0
7849
const values = []
@@ -90,3 +61,32 @@ function mediaTransform(rawValue: string) {
9061
values.push(rawValue.slice(lastIndex, rawValue.length))
9162
return values
9263
}
64+
65+
export const transform = (rawValue: any): any => {
66+
if (typeof rawValue !== 'string') return rawValue
67+
let matches
68+
let lastIndex = 0
69+
const values = []
70+
while ((matches = MATCH_REGEXP.exec(rawValue))) {
71+
const [, prop, colon, value, imp, semi, media, query, brace] = matches
72+
if (media) {
73+
values.push(rawValue.slice(lastIndex, matches.index))
74+
values.push(media)
75+
mediaTransform(query).forEach((v) => values.push(v))
76+
values.push(brace)
77+
lastIndex = matches.index + matches[0].length
78+
} else {
79+
const getter = (propGetters as any)[prop]
80+
if (getter) {
81+
values.push(rawValue.slice(lastIndex, matches.index))
82+
values.push(
83+
(p: object) =>
84+
`${prop}${colon}${getter(value)(p)}${imp || ''}${semi}`,
85+
)
86+
lastIndex = matches.index + matches[0].length
87+
}
88+
}
89+
}
90+
values.push(rawValue.slice(lastIndex, rawValue.length))
91+
return values
92+
}

packages/emotion/src/breakpoints.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,12 @@ import { useTheme } from '@emotion/react'
99

1010
export { useViewportWidth } from '@xstyled/core'
1111

12-
export const useScreens = (): Screens => {
13-
return useThemeScreens(useTheme())
14-
}
12+
export const useScreens = (): Screens => useThemeScreens(useTheme())
1513

16-
export const useBreakpoint = (): string | null => {
17-
return useThemeBreakpoint(useTheme())
18-
}
14+
export const useBreakpoint = (): string | null => useThemeBreakpoint(useTheme())
1915

20-
export const useUp = (key: string | number): boolean => {
21-
return useThemeUp(useTheme(), key)
22-
}
16+
export const useUp = (key: string | number): boolean =>
17+
useThemeUp(useTheme(), key)
2318

24-
export const useDown = (key: string | number): boolean => {
25-
return useThemeDown(useTheme(), key)
26-
}
19+
export const useDown = (key: string | number): boolean =>
20+
useThemeDown(useTheme(), key)

packages/emotion/src/createGlobalStyle.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import { css } from './css'
77
export const createGlobalStyle = <P extends object = {}>(
88
...styles: Parameters<typeof css>
99
) => {
10-
return function GlobalStyle(props: P) {
10+
const GlobalStyle = (props: P) => {
1111
const theme = useTheme()
1212
return <Global styles={css(...styles)({ theme, ...props })} />
1313
}
14+
GlobalStyle.displayName = 'GlobalStyle'
15+
return GlobalStyle
1416
}

packages/emotion/src/createShouldForwardProp.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import * as React from 'react'
2+
import emStyled, { CreateStyledComponent, CreateStyled } from '@emotion/styled'
3+
import { Theme } from '@emotion/react'
4+
import { StyleGenerator, StyleGeneratorProps } from '@xstyled/system'
5+
import { BoxElements } from '@xstyled/core'
6+
import { css } from './css'
7+
8+
const flattenArgs = (arg: any, props: any): any => {
9+
if (typeof arg === 'function') return flattenArgs(arg(props), props)
10+
if (Array.isArray(arg)) return arg.map((arg) => flattenArgs(arg, props))
11+
return arg
12+
}
13+
14+
const getCreateStyle = (baseCreateStyle: any, generator?: StyleGenerator) => {
15+
if (!generator) {
16+
return (strings: any, ...args: any) =>
17+
baseCreateStyle((props: any) =>
18+
css(strings, ...flattenArgs(args, props))(props),
19+
)
20+
}
21+
return (strings: any, ...args: any) => {
22+
if (Array.isArray(strings)) {
23+
// The tagged template literal should receive an equal number of
24+
// additional separators.
25+
strings = [...strings, '\n']
26+
}
27+
args = [...args, generator]
28+
return baseCreateStyle((props: any) =>
29+
css(strings, ...flattenArgs(args, props))(props),
30+
)
31+
}
32+
}
33+
34+
type BoxStyledTags<TProps extends object> = {
35+
[Tag in keyof BoxElements]: CreateStyledComponent<
36+
TProps & { as?: React.ElementType; theme?: Theme },
37+
JSX.IntrinsicElements[BoxElements[Tag]]
38+
>
39+
}
40+
41+
export interface CreateXStyled<TProps extends object = {}>
42+
extends CreateStyled,
43+
BoxStyledTags<TProps> {}
44+
45+
const createShouldForwardProp = (
46+
generator: StyleGenerator,
47+
): ((prop: string) => boolean) => {
48+
const propSet = new Set<string>(generator.meta.props)
49+
return (prop: string) =>
50+
prop !== 'as' && !prop.startsWith('$') && !propSet.has(prop)
51+
}
52+
53+
export const createBaseStyled = <TGen extends StyleGenerator>(
54+
generator?: TGen,
55+
): CreateXStyled<StyleGeneratorProps<TGen>> => {
56+
const defaultOptions = generator
57+
? {
58+
shouldForwardProp: createShouldForwardProp(generator),
59+
}
60+
: {}
61+
return ((component: any, options: any) =>
62+
getCreateStyle(
63+
emStyled(component, { ...defaultOptions, ...options }),
64+
generator,
65+
)) as CreateXStyled<StyleGeneratorProps<TGen>>
66+
}
67+
68+
export const createStyled = <TGen extends StyleGenerator>(
69+
generator: TGen,
70+
): CreateXStyled<StyleGeneratorProps<TGen>> => {
71+
const styled = createBaseStyled()
72+
const xstyled = createBaseStyled(generator)
73+
styled.box = xstyled('div')
74+
Object.keys(emStyled).forEach((key) => {
75+
// @ts-ignore
76+
styled[key] = styled(key)
77+
// @ts-ignore
78+
styled[`${key}Box`] = xstyled(key)
79+
})
80+
return styled
81+
}

packages/emotion/src/createX.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
/* eslint-disable no-continue, no-loop-func, no-cond-assign */
1+
/* eslint-disable @typescript-eslint/ban-types */
22
import * as React from 'react'
33
import { Theme } from '@emotion/react'
44
import emStyled, { StyledComponent } from '@emotion/styled'
55
import { compose, StyleGenerator } from '@xstyled/system'
6-
import { createShouldForwardProp } from './createShouldForwardProp'
7-
import { styledWithGenerator } from './styled'
6+
import { createBaseStyled } from './createStyled'
87

98
type JSXElementKeys = keyof JSX.IntrinsicElements
109

@@ -24,17 +23,13 @@ export interface X<TProps extends object> extends JSXElements<TProps> {
2423
export const createX: CreateX = <TProps extends object>(
2524
generator: StyleGenerator,
2625
) => {
27-
// @ts-ignore
26+
const styled = createBaseStyled(generator)
2827
const x: X<TProps> = {
2928
extend: (...generators) => createX(compose(generator, ...generators)),
30-
}
31-
32-
const shouldForwardProp = createShouldForwardProp(generator)
33-
29+
} as X<TProps>
3430
Object.keys(emStyled).forEach((tag) => {
3531
// @ts-ignore
36-
x[tag] = styledWithGenerator(tag, { shouldForwardProp }, generator)``
32+
x[tag] = styled(tag)``
3733
})
38-
3934
return x
4035
}

packages/emotion/src/styled.ts

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,4 @@
1-
/* eslint-disable no-continue, no-loop-func, no-cond-assign */
2-
import * as React from 'react'
3-
import emStyled, { CreateStyledComponent, CreateStyled } from '@emotion/styled'
4-
import { Theme } from '@emotion/react'
5-
import { StyleGenerator, SystemProps, system } from '@xstyled/system'
6-
import { BoxElements } from '@xstyled/core'
7-
import { createShouldForwardProp } from './createShouldForwardProp'
8-
import { css } from './css'
1+
import { system } from '@xstyled/system'
2+
import { createStyled } from './createStyled'
93

10-
function flattenArgs(arg: any, props: any): any {
11-
if (typeof arg === 'function') return flattenArgs(arg(props), props)
12-
if (Array.isArray(arg)) return arg.map((arg) => flattenArgs(arg, props))
13-
return arg
14-
}
15-
16-
function getCreateStyle(baseCreateStyle: any, ...generators: StyleGenerator[]) {
17-
const createStyle = generators.length
18-
? (strings: any, ...args: any) => {
19-
if (Array.isArray(strings)) {
20-
// The tagged template literal should receive an equal number of
21-
// additional separators.
22-
strings = strings.concat(generators.map(() => '\n'))
23-
}
24-
args = args.concat(generators)
25-
return baseCreateStyle((props: any) =>
26-
css(strings, ...flattenArgs(args, props))(props),
27-
)
28-
}
29-
: (strings: any, ...args: any) =>
30-
baseCreateStyle((props: any) =>
31-
css(strings, ...flattenArgs(args, props))(props),
32-
)
33-
return createStyle
34-
}
35-
36-
type BoxStyledTags = {
37-
[Tag in keyof BoxElements]: CreateStyledComponent<
38-
SystemProps<Theme> & { as?: React.ElementType; theme?: Theme },
39-
JSX.IntrinsicElements[BoxElements[Tag]]
40-
>
41-
}
42-
43-
interface CreateXStyled extends CreateStyled, BoxStyledTags {}
44-
45-
// @ts-ignore
46-
export const styled: CreateXStyled = (component: any, options: any) =>
47-
getCreateStyle(emStyled(component, options))
48-
49-
// exported for x.* but not for xstyled API
50-
// @ts-ignore
51-
export const styledWithGenerator: CreateXStyled = (
52-
component: any,
53-
options: any,
54-
generator: StyleGenerator,
55-
) => getCreateStyle(emStyled(component, options), generator)
56-
57-
const shouldForwardProp = createShouldForwardProp(system)
58-
59-
// @ts-ignore
60-
styled.box = styledWithGenerator('div', { shouldForwardProp }, system)
61-
62-
Object.keys(emStyled).forEach((key) => {
63-
// @ts-ignore
64-
styled[key] = styled(key)
65-
// @ts-ignore
66-
styled[`${key}Box`] = styledWithGenerator(key, { shouldForwardProp }, system)
67-
})
4+
export const styled = createStyled(system)

packages/styled-components/src/createShouldForwardProp.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)