import { StyleSheet, css as stylesheetToClassNames, } from 'aphrodite'; import { Map } from 'immutable'; const Prefixer = require('inline-style-prefixer'); import { DEVELOPMENT } from '../config'; const prefixer = new Prefixer({ userAgent: navigator.userAgent }); function prefixStyles(obj: Object) { return prefixer.prefix(obj); } export interface IStyleProps { className?: string; style?: Object; } let knownStylesheets = Map(); export function stylesheet(styles: T): T { const sheet = StyleSheet.create(styles as any); for (const key in sheet) { const originalObject = (styles as any)[key]; knownStylesheets = knownStylesheets.set(originalObject, sheet[key]); } return styles; } function knownStyle(obj: Object) { return knownStylesheets.get(obj); } export type IPossibleStyle = Object | string | null | undefined | false; function flattenStyleReducer(sum: any, style: IPossibleStyle) { if (!style) { return sum; } return Object.assign(sum, style); } function flattenStyles(styles: Array): Object { return styles.reduce(flattenStyleReducer, {}); } // TODO: Find a way to quickly memoize this. export const css = (...styles: Array): IStyleProps => { const fromStylesheet = styles.filter((style: IPossibleStyle) => style && typeof style !== 'string' && knownStyle(style)); const notFromStylesheet = styles.filter((style: IPossibleStyle) => style && typeof style !== 'string' && !knownStyle(style)); const fromClassName = styles.filter((style: IPossibleStyle) => style && typeof style === 'string'); const prefixedInline = notFromStylesheet.map(prefixStyles); if (DEVELOPMENT) { let gotInlineStyle = false; for (const style of styles) { if (!style) { continue; } if (knownStyle(style) || typeof style === 'string') { if (gotInlineStyle) { throw new Error('Tried to add a class-based style AFTER an inline style. Precedence will be confusing. Please refactor'); } } else { gotInlineStyle = true; } } // debugger; return { style: { ...flattenStyles(fromStylesheet), ...flattenStyles(prefixedInline), }, ...( fromClassName.length > 0 ? { className: fromClassName.join(' '), } : {}), }; } else { const classNames = fromClassName.concat([ stylesheetToClassNames(fromStylesheet.map(knownStyle)), ]).join(' '); return { ...( classNames.length > 0 ? { className: classNames, } : {}), style: flattenStyles(prefixedInline), }; } };