@emotion/css
Version:
The Next Generation of CSS-in-JS.
162 lines (144 loc) • 3.76 kB
JavaScript
// @flow
import createCache from '@emotion/cache'
import { serializeStyles } from '@emotion/serialize'
import {
insertStyles,
getRegisteredStyles,
type EmotionCache,
type SerializedStyles
} from '@emotion/utils'
function insertWithoutScoping(cache, serialized: SerializedStyles) {
if (cache.inserted[serialized.name] === undefined) {
return cache.insert('', serialized, cache.sheet, true)
}
}
function merge(registered: Object, css: (*) => string, className: string) {
const registeredStyles = []
const rawClassName = getRegisteredStyles(
registered,
registeredStyles,
className
)
if (registeredStyles.length < 2) {
return className
}
return rawClassName + css(registeredStyles)
}
export type Interpolation = any
export type Interpolations = Array<Interpolation>
type CreateStyles<ReturnValue> = (...args: Interpolations) => ReturnValue
type ClassNameArg =
| string
| boolean
| { [key: string]: boolean | void | null }
| Array<ClassNameArg>
| void
| null
declare class StyleSheet {
insert(rule: string): void;
flush(): void;
speedy(newVal: boolean): void;
tags: Array<HTMLStyleElement>;
isSpeedy: number;
ctr: number;
}
export type Emotion = {
css: CreateStyles<string>,
cx: (...classNames: Array<ClassNameArg>) => string,
flush: () => void,
hydrate: (ids: Array<string>) => void,
injectGlobal: CreateStyles<void>,
keyframes: CreateStyles<string>,
sheet: StyleSheet,
cache: EmotionCache,
merge: *,
getRegisteredStyles: *
}
let createEmotion = (options: *): Emotion => {
let cache = createCache(options)
// $FlowFixMe
cache.sheet.speedy = function(value: boolean) {
if (process.env.NODE_ENV !== 'production' && this.ctr !== 0) {
throw new Error('speedy must be changed before any rules are inserted')
}
this.isSpeedy = value
}
cache.compat = true
let css = (...args) => {
let serialized = serializeStyles(args, cache.registered, undefined)
insertStyles(cache, serialized, false)
return `${cache.key}-${serialized.name}`
}
let keyframes = (...args) => {
let serialized = serializeStyles(args, cache.registered)
let animation = `animation-${serialized.name}`
insertWithoutScoping(cache, {
name: serialized.name,
styles: `@keyframes ${animation}{${serialized.styles}}`
})
return animation
}
let injectGlobal = (...args) => {
let serialized = serializeStyles(args, cache.registered)
insertWithoutScoping(cache, serialized)
}
let cx = (...args) => {
return merge(cache.registered, css, classnames(args))
}
return {
css,
cx,
injectGlobal,
keyframes,
hydrate(ids: Array<string>) {
ids.forEach(key => {
cache.inserted[key] = true
})
},
flush() {
cache.registered = {}
cache.inserted = {}
cache.sheet.flush()
},
// $FlowFixMe
sheet: cache.sheet,
cache,
getRegisteredStyles: getRegisteredStyles.bind(null, cache.registered),
merge: merge.bind(null, cache.registered, css)
}
}
let classnames = args => {
let cls = ''
for (let i = 0; i < args.length; i++) {
let arg = args[i]
if (arg == null) continue
let toAdd
switch (typeof arg) {
case 'boolean':
break
case 'object': {
if (Array.isArray(arg)) {
toAdd = classnames(arg)
} else {
toAdd = ''
for (const k in arg) {
if (arg[k] && k) {
toAdd && (toAdd += ' ')
toAdd += k
}
}
}
break
}
default: {
toAdd = arg
}
}
if (toAdd) {
cls && (cls += ' ')
cls += toAdd
}
}
return cls
}
export default createEmotion