diff --git a/app/emotion-cache-provider.js b/app/emotion-cache-provider.js new file mode 100644 index 0000000..e2229ed --- /dev/null +++ b/app/emotion-cache-provider.js @@ -0,0 +1,88 @@ +'use client' + +import * as React from 'react' +import PropTypes from 'prop-types' +import createCache from '@emotion/cache' +import {useServerInsertedHTML} from 'next/navigation' +import {CacheProvider as DefaultCacheProvider} from '@emotion/react' + +export default function NextAppDirEmotionCacheProvider(props) { + const {options, CacheProvider = DefaultCacheProvider, children} = props + + const [registry] = React.useState(() => { + const cache = createCache(options) + cache.compat = true + const prevInsert = cache.insert + let inserted = [] + cache.insert = (...args) => { + const [selector, serialized] = args + if (cache.inserted[serialized.name] === undefined) { + inserted.push({ + name: serialized.name, + isGlobal: selector === '', + }) + } + + return prevInsert(...args) + } + + const flush = () => { + const prevInserted = inserted + inserted = [] + return prevInserted + } + + return {cache, flush} + }) + + useServerInsertedHTML(() => { + const inserted = registry.flush() + if (inserted.length === 0) { + return null + } + + let styles = '' + let dataEmotionAttribute = registry.cache.key + + const globals = [] + + for (const {name, isGlobal} of inserted) { + const style = registry.cache.inserted[name] + + if (typeof style !== 'boolean') { + if (isGlobal) { + globals.push({name, style}) + } else { + styles += style + dataEmotionAttribute += ` ${name}` + } + } + } + + return ( + <> + {globals.map(({name, style}) => ( +