global.js
2.69 KB
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
// @flow
import * as React from 'react'
import { withCSSContext } from './context'
import { isBrowser, type CSSContextType } from '@emotion/utils'
import { StyleSheet } from '@emotion/sheet'
import { serializeStyles } from '@emotion/serialize'
type GlobalProps = {
styles: Object | Array<Object>
}
export let Global: React.StatelessFunctionalComponent<
GlobalProps
> = /* #__PURE__ */ withCSSContext((props: GlobalProps, context) => {
return <InnerGlobal styles={props.styles} context={context} />
})
type InnerGlobalProps = {
styles: Object | Array<Object>,
context: CSSContextType
}
// maintain place over rerenders.
// initial render from browser, insertBefore context.sheet.tags[0] or if a style hasn't been inserted there yet, appendChild
// initial client-side render from SSR, use place of hydrating tag
class InnerGlobal extends React.Component<InnerGlobalProps> {
styleName: string
sheet: StyleSheet
componentDidMount() {
this.updateStyles()
}
componentDidUpdate() {
this.updateStyles()
}
updateStyles() {
let serialized = serializeStyles(this.props.context.registered, [
this.props.styles
])
if (serialized.name === this.styleName) {
return
}
this.styleName = serialized.name
if (!this.sheet) {
this.sheet = new StyleSheet({
key: `${this.props.context.key}-global`,
nonce: this.props.context.sheet.nonce,
container: this.props.context.sheet.container
})
// $FlowFixMe
let node: HTMLStyleElement | null = document.querySelector(
`style[data-emotion-${this.props.context.key}="${serialized.name}"]`
)
if (node !== null) {
this.sheet.tags.push(node)
}
// $FlowFixMe
if (this.props.context.sheet.tags.length) {
this.sheet.before = this.props.context.sheet.tags[0]
}
}
let rules = this.props.context.stylis(``, serialized.styles)
if (this.sheet.tags.length) {
// if this doesn't exist then it will be null so the style element will be appended
this.sheet.before = this.sheet.tags[0].nextElementSibling
this.sheet.flush()
}
rules.forEach(this.sheet.insert, this.sheet)
}
componentWillUnmount() {
this.sheet.flush()
}
render() {
if (!isBrowser) {
const serialized = serializeStyles(this.props.context.registered, [
this.props.styles
])
let rules = this.props.context.stylis(``, serialized.styles)
return (
<style
{...{
[`data-emotion-${this.props.context.key}`]: serialized.name,
dangerouslySetInnerHTML: { __html: rules.join('') },
nonce: this.props.context.sheet.nonce
}}
/>
)
}
return null
}
}