// @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 type CreateStyles = (...args: Interpolations) => ReturnValue type ClassNameArg = | string | boolean | { [key: string]: boolean | void | null } | Array | void | null declare class StyleSheet { insert(rule: string): void; flush(): void; speedy(newVal: boolean): void; tags: Array; isSpeedy: number; ctr: number; } export type Emotion = { css: CreateStyles, cx: (...classNames: Array) => string, flush: () => void, hydrate: (ids: Array) => void, injectGlobal: CreateStyles, keyframes: CreateStyles, 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) { 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