Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More tests, use fns from utils and rework core #191

Merged
merged 18 commits into from
Jul 28, 2017
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/glamor/CSSPropertyOperations/CSSProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ let prefixes = ['Webkit', 'ms', 'Moz', 'O']

// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
keys(isUnitlessNumber).forEach(function (prop) {
forEach(keys(isUnitlessNumber), function (prop) {
forEach(prefixes, function (prefix) {
isUnitlessNumber[prefixKey(prefix, prop)] = 1
})
Expand Down
7 changes: 5 additions & 2 deletions src/glamor/CSSPropertyOperations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
*/

import dangerousStyleValue from './dangerousStyleValue'
import hyphenateStyleName from 'fbjs/lib/hyphenateStyleName'
import memoizeStringOnly from 'fbjs/lib/memoizeStringOnly'

export const processStyleName = memoizeStringOnly(hyphenateStyleName)
const hyphenateRegex = /[A-Z]|^ms/g

export const processStyleName = memoizeStringOnly(styleName =>
styleName.replace(hyphenateRegex, '-$&').toLowerCase()
)

if (process.env.NODE_ENV !== 'production') {
const warning = require('fbjs/lib/warning')
Expand Down
2 changes: 1 addition & 1 deletion src/glamor/clean.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function cleanObject (object) {

let acc = {}
let hasFalsy = false
forEach(keys(object), (value) => {
forEach(keys(object), value => {
const filteredValue = clean(value)
if (filteredValue === null || filteredValue !== value) {
hasFalsy = true
Expand Down
95 changes: 42 additions & 53 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import { StyleSheet } from './sheet'
import { forEach, map, reduce } from './utils'
import { forEach, map, reduce, keys } from './utils'
import { hashString as hash, hashObject } from './hash'
import { createMarkupForStyles } from './glamor/CSSPropertyOperations'
import clean from './glamor/clean.js'
Expand Down Expand Up @@ -45,27 +45,15 @@ function _getRegistered (rule) {
return rule
}

// The idea on how to merge object class names come from glamorous
// 💄
// https://github.com/paypal/glamorous/blob/master/src/get-glamor-classname.js
function getEmotionStylesFromClassName (className) {
const id = className.trim().slice('css-'.length)
if (sheet.registered[id]) {
return sheet.registered[id].style
} else {
return []
}
}

function buildStyles (objs) {
let computedClassName = ''
let objectStyles = []

// This needs to be moved into the core
forEach(objs, (cls): void => {
if (typeof cls === 'string') {
if (cls.trim().indexOf('css-') === 0) {
objectStyles.push(getEmotionStylesFromClassName(cls))
const match = emotionClassRegex.exec(cls)
if (match) {
objectStyles.push(ruleCache[match[1]])
} else {
computedClassName && (computedClassName += ' ')
computedClassName += cls
Expand Down Expand Up @@ -118,7 +106,7 @@ export function injectGlobal (
// injectGlobal is flattened by postcss
// we don't support nested selectors on objects
forEach(combined, obj => {
forEach(Object.keys(obj), selector => {
forEach(keys(obj), selector => {
insertRawRule(`${selector} {${createMarkupForStyles(obj[selector])}}`)
})
})
Expand All @@ -141,7 +129,7 @@ export function fontFace (
function insertKeyframe (spec) {
if (!inserted[spec.id]) {
const inner = map(
Object.keys(spec.keyframes),
keys(spec.keyframes),
kf => `${kf} {${createMarkupForStyles(spec.keyframes[kf])}}`
).join('')

Expand Down Expand Up @@ -181,16 +169,12 @@ type EmotionRule = { [string]: any }

type CSSRuleList = Array<EmotionRule>

type EmotionClassName = {
[string]: any
}

let cachedCss: (rules: CSSRuleList) => EmotionClassName =
let cachedCss: (rules: CSSRuleList) => EmotionRule =
typeof WeakMap !== 'undefined' ? multiIndexCache(_css) : _css

// 🍩
// https://github.com/threepointone/glamor
export function objStyle (...rules: CSSRuleList): EmotionClassName {
export function objStyle (...rules: CSSRuleList): EmotionRule {
rules = clean(rules)
if (!rules) {
return nullrule
Expand All @@ -211,21 +195,22 @@ function _css (rules) {
return toRule(spec)
}

const emotionClassRegex = /css-([a-zA-Z0-9]+)/

// of shape { 'data-css-<id>': '' }
export function isLikeRule (rule: EmotionRule) {
let keys = Object.keys(rule).filter(x => x !== 'toString')
if (keys.length !== 1) {
let ruleKeys = keys(rule).filter(x => x !== 'toString')
if (ruleKeys.length !== 1) {
return false
}
return !!/css-([a-zA-Z0-9]+)/.exec(keys[0])
return !!emotionClassRegex.exec(ruleKeys[0])
}

// extracts id from a { 'css-<id>': ''} like object
export function idFor (rule: EmotionRule) {
let keys = Object.keys(rule).filter(x => x !== 'toString')
if (keys.length !== 1) throw new Error('not a rule')
let regex = /css-([a-zA-Z0-9]+)/
let match = regex.exec(keys[0])
let ruleKeys = keys(rule).filter(x => x !== 'toString')
if (ruleKeys.length !== 1) throw new Error('not a rule')
let match = emotionClassRegex.exec(ruleKeys[0])
if (!match) throw new Error('not a rule')
return match[1]
}
Expand All @@ -236,21 +221,22 @@ function selector (id: string, path: string = '') {
}
if (!path) return `.css-${id}`

let x = path
.split(',')
.map(
x =>
x.indexOf('&') >= 0 ? x.replace(/&/gm, `.css-${id}`) : `.css-${id}${x}`
)
.join(',')
let x = map(
path.split(','),
x =>
x.indexOf('&') >= 0 ? x.replace(/&/gm, `.css-${id}`) : `.css-${id}${x}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably hoist this callback and the regex inside.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't because it uses id

).join(',')

return x
}

function deconstruct (style) {
// we can be sure it's not infinitely nested here
let plain, selects, medias, supports
Object.keys(style).forEach(key => {
let plain
let selects
let medias
let supports
forEach(keys(style), key => {
if (key.indexOf('&') >= 0) {
selects = selects || {}
selects[key] = style[key]
Expand All @@ -276,17 +262,17 @@ function deconstructedStyleToCSS (id, style) {
css.push(`${selector(id)}{${createMarkupForStyles(plain)}}`)
}
if (selects) {
Object.keys(selects).forEach((key: string) =>
forEach(keys(selects), (key: string) =>
css.push(`${selector(id, key)}{${createMarkupForStyles(selects[key])}}`)
)
}
if (medias) {
Object.keys(medias).forEach(key =>
forEach(keys(medias), key =>
css.push(`${key}{${deconstructedStyleToCSS(id, medias[key]).join('')}}`)
)
}
if (supports) {
Object.keys(supports).forEach(key =>
forEach(keys(supports), key =>
css.push(`${key}{${deconstructedStyleToCSS(id, supports[key]).join('')}}`)
)
}
Expand All @@ -298,7 +284,7 @@ function insert (spec) {
if (!inserted[spec.id]) {
inserted[spec.id] = true
let deconstructed = deconstruct(spec.style)
deconstructedStyleToCSS(spec.id, deconstructed).map(cssRule =>
map(deconstructedStyleToCSS(spec.id, deconstructed), cssRule =>
sheet.insert(cssRule)
)
}
Expand Down Expand Up @@ -342,9 +328,11 @@ function joinSelectors (a, b) {
let as = map(a.split(','), a => (!(a.indexOf('&') >= 0) ? '&' + a : a))
let bs = map(b.split(','), b => (!(b.indexOf('&') >= 0) ? '&' + b : b))

return bs
.reduce((arr, b) => arr.concat(as.map(a => b.replace(/&/g, a))), [])
.join(',')
return reduce(
bs,
(arr, b) => arr.concat(map(as, a => b.replace(/&/g, a))),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could hoist this up as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't because it uses a

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, i might be wrong

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't hoist it because it uses as

[]
).join(',')
}

function joinMediaQueries (a, b) {
Expand All @@ -366,10 +354,11 @@ function joinSupports (a, b) {
// flatten a nested array
function flatten (inArr) {
let arr = []
for (let i = 0; i < inArr.length; i++) {
if (Array.isArray(inArr[i])) arr = arr.concat(flatten(inArr[i]))
else arr = arr.concat(inArr[i])
}
forEach(inArr, val => {
if (Array.isArray(val)) arr = arr.concat(flatten(val))
else arr = arr.concat(val)
})

return arr
}

Expand All @@ -380,7 +369,7 @@ function build (dest, { selector = '', mq = '', supp = '', src = {} }) {
}
src = flatten(src)

src.forEach(_src => {
forEach(src, _src => {
if (isLikeRule(_src)) {
let reg = _getRegistered(_src)
if (reg.type !== 'css') {
Expand All @@ -392,7 +381,7 @@ function build (dest, { selector = '', mq = '', supp = '', src = {} }) {
if (_src && _src.composes) {
build(dest, { selector, mq, supp, src: _src.composes })
}
Object.keys(_src || {}).forEach(key => {
forEach(keys(_src || {}), key => {
if (isSelector(key)) {
build(dest, {
selector: joinSelectors(selector, key),
Expand Down
6 changes: 4 additions & 2 deletions src/sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ styleSheet.flush()

*/

import { forEach } from './utils'

function last (arr) {
return arr[arr.length - 1]
}
Expand Down Expand Up @@ -157,7 +159,7 @@ Object.assign(StyleSheet.prototype, {
},
flush () {
if (isBrowser) {
this.tags.forEach(tag => tag.parentNode.removeChild(tag))
forEach(this.tags, tag => tag.parentNode.removeChild(tag))
this.tags = []
this.sheet = null
this.ctr = 0
Expand All @@ -173,7 +175,7 @@ Object.assign(StyleSheet.prototype, {
return this.sheet.cssRules
}
let arr = []
this.tags.forEach(tag =>
forEach(this.tags, tag =>
arr.splice(arr.length, 0, ...Array.from(sheetForTag(tag).cssRules))
)
return arr
Expand Down
71 changes: 71 additions & 0 deletions test/__snapshots__/css.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`css @supports 1`] = `
<div
className="css-1u5pet7"
/>
`;

exports[`css composes 1`] = `
.glamor-0 {
display: -webkit-box;
Expand Down Expand Up @@ -60,6 +66,30 @@ exports[`css composes with undefined values 1`] = `
/>
`;

exports[`css composition stuff 1`] = `
.glamor-0 {
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}

<div
className="glamor-0"
/>
`;

exports[`css composition stuff 2`] = `
.glamor-0 {
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}

<div
className="glamor-0"
/>
`;

exports[`css computed key is only dynamic 1`] = `
.glamor-0 {
font-size: 10px;
Expand All @@ -71,6 +101,17 @@ exports[`css computed key is only dynamic 1`] = `
/>
`;

exports[`css css variables 1`] = `
.glamor-0 {
--some-var: 1px;
width: var(--some-var);
}

<div
className="glamor-0"
/>
`;

exports[`css flushes correctly 1`] = `
.glamor-0 {
display: -webkit-box;
Expand Down Expand Up @@ -126,6 +167,36 @@ exports[`css handles objects 1`] = `
/>
`;

exports[`css nested array 1`] = `
.glamor-0 {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}

<div
className="glamor-0"
/>
`;

exports[`css nested at rules 1`] = `
@media (min-width: 420px) {
.glamor-0 {
color: pink;
}
}

@media (min-width: 420px) and (max-width: 500px) {
.glamor-0 {
color: hotpink;
}
}

<div
className="glamor-0"
/>
`;

exports[`css null rule 1`] = `
<div
className="css-nil"
Expand Down
Loading