/
jsx.js
169 lines (146 loc) Β· 4.49 KB
/
jsx.js
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// @flow
import * as React from 'react'
import { withEmotionCache } from './context'
import { ThemeContext } from './theming'
import { getRegisteredStyles, insertStyles } from '@emotion/utils'
import { isBrowser } from './utils'
import { serializeStyles } from '@emotion/serialize'
// those identifiers come from error stacks, so they have to be valid JS identifiers
// thus we only need to replace what is a valid character for JS, but not for CSS
const sanitizeIdentifier = (identifier: string) =>
identifier.replace(/\$/g, '-')
let typePropName = '__EMOTION_TYPE_PLEASE_DO_NOT_USE__'
let labelPropName = '__EMOTION_LABEL_PLEASE_DO_NOT_USE__'
let hasOwnProperty = Object.prototype.hasOwnProperty
let Emotion = withEmotionCache((props, cache, ref) => {
let cssProp = props.css
if (typeof cssProp === 'function') {
cssProp = cssProp(React.useContext(ThemeContext))
}
// so that using `css` from `emotion` and passing the result to the css prop works
// not passing the registered cache to serializeStyles because it would
// make certain babel optimisations not possible
if (typeof cssProp === 'string' && cache.registered[cssProp] !== undefined) {
cssProp = cache.registered[cssProp]
}
let type = props[typePropName]
let registeredStyles = [cssProp]
let className = ''
if (typeof props.className === 'string') {
className = getRegisteredStyles(
cache.registered,
registeredStyles,
props.className
)
} else if (props.className != null) {
className = `${props.className} `
}
let serialized = serializeStyles(registeredStyles)
if (
process.env.NODE_ENV !== 'production' &&
serialized.name.indexOf('-') === -1
) {
let labelFromStack = props[labelPropName]
if (labelFromStack) {
serialized = serializeStyles([
serialized,
'label:' + labelFromStack + ';'
])
}
}
const rules = insertStyles(cache, serialized, typeof type === 'string')
className += `${cache.key}-${serialized.name}`
const newProps = {}
for (let key in props) {
if (
hasOwnProperty.call(props, key) &&
key !== 'css' &&
key !== typePropName &&
(process.env.NODE_ENV === 'production' || key !== labelPropName)
) {
newProps[key] = props[key]
}
}
newProps.ref = ref
newProps.className = className
const ele = React.createElement(type, newProps)
if (!isBrowser && rules !== undefined) {
let serializedNames = serialized.name
let next = serialized.next
while (next !== undefined) {
serializedNames += ' ' + next.name
next = next.next
}
return (
<React.Fragment>
<style
{...{
[`data-emotion-${cache.key}`]: serializedNames,
dangerouslySetInnerHTML: { __html: rules },
nonce: cache.sheet.nonce
}}
/>
{ele}
</React.Fragment>
)
}
return ele
})
if (process.env.NODE_ENV !== 'production') {
Emotion.displayName = 'EmotionCssPropInternal'
}
// $FlowFixMe
export const jsx: typeof React.createElement = function(
type: React.ElementType,
props: Object
) {
let args = arguments
if (props == null || !hasOwnProperty.call(props, 'css')) {
// $FlowFixMe
return React.createElement.apply(undefined, args)
}
if (
process.env.NODE_ENV !== 'production' &&
typeof props.css === 'string' &&
// check if there is a css declaration
props.css.indexOf(':') !== -1
) {
throw new Error(
`Strings are not allowed as css prop values, please wrap it in a css template literal from '@emotion/core' like this: css\`${
props.css
}\``
)
}
let argsLength = args.length
let createElementArgArray = new Array(argsLength)
createElementArgArray[0] = Emotion
let newProps = {}
for (let key in props) {
if (hasOwnProperty.call(props, key)) {
newProps[key] = props[key]
}
}
newProps[typePropName] = type
if (process.env.NODE_ENV !== 'production') {
let error = new Error()
if (error.stack) {
// chrome
let match = error.stack.match(
/at (?:Object\.|)jsx.*\n\s+at ([A-Z][A-Za-z$]+) /
)
if (!match) {
// safari and firefox
match = error.stack.match(/^.*\n([A-Z][A-Za-z$]+)@/)
}
if (match) {
newProps[labelPropName] = sanitizeIdentifier(match[1])
}
}
}
createElementArgArray[1] = newProps
for (let i = 2; i < argsLength; i++) {
createElementArgArray[i] = args[i]
}
// $FlowFixMe
return React.createElement.apply(null, createElementArgArray)
}