-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathstyled.ts
106 lines (84 loc) Β· 2.98 KB
/
styled.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React from 'react'
import { interleave } from './utils'
import { ThemeContext } from '@emotion/react'
import { createCss } from './css'
import { AbstractStyleSheet } from './types'
let testOmitPropsOnComponent = (prop: string) =>
prop !== 'theme' && prop !== 'as'
interface CreateStyledOptions {
getShouldForwardProp(cmp: React.ElementType): (prop: string) => boolean
}
interface StyledOptions {
shouldForwardProp?(prop: string): boolean
}
type StyledProps = Record<string, unknown> & {
as?: React.ElementType
}
export function createStyled(
StyleSheet: AbstractStyleSheet,
options?: CreateStyledOptions
) {
const getShouldForwardProp =
options?.getShouldForwardProp ?? (() => testOmitPropsOnComponent)
const css = createCss(StyleSheet)
return function createEmotion(
component: React.ElementType,
options?: StyledOptions
) {
let shouldForwardProp =
options && options.shouldForwardProp
? options.shouldForwardProp
: undefined
let defaultShouldForwardProp =
shouldForwardProp || getShouldForwardProp(component)
let shouldUseAs = !defaultShouldForwardProp('as')
return function createStyledComponent(...rawStyles: any[]) {
let styles: any[]
if (rawStyles[0] == null || rawStyles[0].raw === undefined) {
styles = rawStyles
} else {
styles = interleave(rawStyles as [any, ...any[]])
}
// do we really want to use the same infra as the web since it only really uses theming?
let Styled: React.FC<StyledProps> = props => {
const finalTag =
(shouldUseAs && (props.as as React.ElementType)) || component
let mergedProps = props
if (props.theme == null) {
mergedProps = {}
for (let key in props) {
mergedProps[key] = props[key]
}
mergedProps.theme = React.useContext(ThemeContext)
}
let finalShouldForwardProp =
shouldUseAs && shouldForwardProp === undefined
? getShouldForwardProp(finalTag)
: defaultShouldForwardProp
let newProps: Record<string, unknown> = {}
for (let key in props) {
if (shouldUseAs && key === 'as') continue
if (finalShouldForwardProp(key)) {
newProps[key] = props[key]
}
}
newProps.style = [css.apply(mergedProps, styles), props.style]
return React.createElement(finalTag, newProps)
}
Styled.displayName = `emotion(${getDisplayName(component)})`
const withComponent = (newComponent: React.ElementType) =>
createEmotion(newComponent)(...styles)
const castedStyled = Styled as typeof Styled & {
withComponent: typeof withComponent
}
castedStyled.withComponent = withComponent
return castedStyled
}
}
}
const getDisplayName = (
primitive: string | { displayName?: string; name?: string }
) =>
typeof primitive === 'string'
? primitive
: primitive.displayName || primitive.name || 'Styled'