Spaces:
Sleeping
Sleeping
File size: 4,597 Bytes
56fda74 |
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 |
import * as React from 'react'
import isDevelopment from '#is-development'
import { withEmotionCache } from './context'
import { Theme, ThemeContext } from './theming'
import { insertStyles } from '@emotion/utils'
import { Options as SheetOptions, StyleSheet } from '@emotion/sheet'
import isBrowser from '#is-browser'
import { useInsertionEffectWithLayoutFallback } from '@emotion/use-insertion-effect-with-fallbacks'
import { Interpolation, serializeStyles } from '@emotion/serialize'
export interface GlobalProps {
styles: Interpolation<Theme>
}
let warnedAboutCssPropForGlobal = false
// 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
export let Global = /* #__PURE__ */ withEmotionCache<GlobalProps>(
(props, cache) => {
if (
isDevelopment &&
!warnedAboutCssPropForGlobal && // check for className as well since the user is
// probably using the custom createElement which
// means it will be turned into a className prop
// I don't really want to add it to the type since it shouldn't be used
(('className' in props && props.className) ||
('css' in props && props.css))
) {
console.error(
"It looks like you're using the css prop on Global, did you mean to use the styles prop instead?"
)
warnedAboutCssPropForGlobal = true
}
let styles = props.styles
let serialized = serializeStyles(
[styles],
undefined,
React.useContext(ThemeContext)
)
if (!isBrowser) {
let serializedNames = serialized.name
let serializedStyles = serialized.styles
let next = serialized.next
while (next !== undefined) {
serializedNames += ' ' + next.name
serializedStyles += next.styles
next = next.next
}
let shouldCache = cache.compat === true
let rules = cache.insert(
``,
{ name: serializedNames, styles: serializedStyles },
cache.sheet,
shouldCache
)
if (shouldCache) {
return null
}
return (
<style
{...{
[`data-emotion`]: `${cache.key}-global ${serializedNames}`,
dangerouslySetInnerHTML: { __html: rules! },
nonce: cache.sheet.nonce
}}
/>
)
}
// yes, i know these hooks are used conditionally
// but it is based on a constant that will never change at runtime
// it's effectively like having two implementations and switching them out
// so it's not actually breaking anything
let sheetRef = React.useRef<
[sheet: StyleSheet, isRehydrating: boolean] | undefined
>()
useInsertionEffectWithLayoutFallback(() => {
const key = `${cache.key}-global`
// use case of https://github.com/emotion-js/emotion/issues/2675
let sheet = new (cache.sheet.constructor as {
new (options: SheetOptions): StyleSheet
})({
key,
nonce: cache.sheet.nonce,
container: cache.sheet.container,
speedy: cache.sheet.isSpeedy
})
let rehydrating = false
let node: HTMLStyleElement | null = document.querySelector(
`style[data-emotion="${key} ${serialized.name}"]`
)
if (cache.sheet.tags.length) {
sheet.before = cache.sheet.tags[0]
}
if (node !== null) {
rehydrating = true
// clear the hash so this node won't be recognizable as rehydratable by other <Global/>s
node.setAttribute('data-emotion', key)
sheet.hydrate([node])
}
sheetRef.current = [sheet, rehydrating]
return () => {
sheet.flush()
}
}, [cache])
useInsertionEffectWithLayoutFallback(() => {
let sheetRefCurrent = sheetRef.current!
let [sheet, rehydrating] = sheetRefCurrent
if (rehydrating) {
sheetRefCurrent[1] = false
return
}
if (serialized.next !== undefined) {
// insert keyframes
insertStyles(cache, serialized.next, true)
}
if (sheet.tags.length) {
// if this doesn't exist then it will be null so the style element will be appended
let element = sheet.tags[sheet.tags.length - 1].nextElementSibling
sheet.before = element
sheet.flush()
}
cache.insert(``, serialized, sheet, false)
}, [cache, serialized.name])
return null
}
)
if (isDevelopment) {
Global.displayName = 'EmotionGlobal'
}
|