From 020add7a5e6f8ee1b8c6afee81da206a1b6bec2b Mon Sep 17 00:00:00 2001 From: natew Date: Mon, 9 Nov 2015 18:21:13 -0800 Subject: [PATCH 1/4] updating for options and tag passing --- lib/__tests__/utils.test.js | 2 +- lib/index.js | 6 +++--- lib/utils.js | 36 +++++++++++++++++++++++++++++------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lib/__tests__/utils.test.js b/lib/__tests__/utils.test.js index 3b91231..0349947 100644 --- a/lib/__tests__/utils.test.js +++ b/lib/__tests__/utils.test.js @@ -44,7 +44,7 @@ describe('utils', () => { const STYLES_CSS = 'width:10px;height:10px;color:tomato;'; describe('#createClassName(obj)', () => { - const className = utils.createClassName( STYLES ); + const className = utils.createClassName( null, null, STYLES ); it('retuns a class string', () => { assert.equal( typeof className, 'string', `${ className } , should be string`); diff --git a/lib/index.js b/lib/index.js index 9c55b27..b89bff9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -9,13 +9,13 @@ import { let globalStylesheet = new Map(); export default { - create( styles, stylesheet = globalStylesheet ) { + create( styles, stylesheet = globalStylesheet, options ) { if ( !(stylesheet instanceof Map) ) throw new Error(`${ stylesheet } should be a Map`); return Object.keys( styles ).reduce( ( acc, key ) => { - let { style, pseudos, mediaQueries } = seperateStyles( styles[key] ); - const className = createClassName( sortObject( style )); + let { style, pseudos, mediaQueries } = seperateStyles( options, key, styles[key] ); + const className = createClassName(options, key, styles); if (className === undefined) { acc[ key ] = ''; diff --git a/lib/utils.js b/lib/utils.js index 38b9dda..7d00014 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -47,7 +47,16 @@ export function extendedToString(num, base) { return (base < 11) ? parseInt(conversion) : conversion; } -export function createClassName(obj) { +export function createClassName(options, tag, obj) { + if (options && options.selectors) { + let selectors = options.selectors.map(({ parent, child }) => { + child = child(tag) + return parent ? `${parent} ${child}` : child + }) + + return selectors.join(' ') + } + const hash = extendedToString( createHash( stringifyObject(obj) ), 62); return hash ? '_' + hash @@ -62,16 +71,28 @@ export function isEmpty(obj) { return !Object.keys(obj).length; } +const pseudos = { + ':active': 'active', + ':hover': 'hover', + ':focus': 'focus', + ':link': 'link', + ':visited': 'visited', + ':checked': 'checked', + ':disabled': 'disabled', + ':empty': 'empty', + ':invalid': 'invalid', +} + export function isPseudo({ style, rule }) { - return rule.charAt(0) === ':' && typeof style === 'object'; + return pseudos[rule] && typeof style === 'object'; } export function isMediaQuery({ style, rule }) { return rule.charAt(0) === '@' && typeof style === 'object'; } -function handle(type, acc, { style, rule }, pseudos = []) { - const hash = createClassName( sortObject( style )); +function handle(options, tag, type, acc, { style, rule }, pseudos = []) { + const hash = createClassName( options, tag, sortObject( style )); const rules = pseudos.length ? [[].concat(rule, style, pseudos)] : rule; @@ -82,7 +103,7 @@ function handle(type, acc, { style, rule }, pseudos = []) { } -export function seperateStyles (styles) { +export function seperateStyles (options, tag, styles) { return Object.keys(styles).reduce( (acc, rule) => { const content = { style: styles[rule], @@ -90,12 +111,13 @@ export function seperateStyles (styles) { }; if ( isPseudo( content ) ) { - return handle('pseudos', acc, content ); + content.rule = pseudos[rule] // translate to :active + return handle(options, tag, 'pseudos', acc, content ); } if ( isMediaQuery( content ) ) { const { style, pseudos } = seperateStyles( content.style ); - return handle('mediaQueries', acc, { rule, style }, pseudos ); + return handle(options, tag, 'mediaQueries', acc, { rule, style }, pseudos ); } acc.style[rule] = content.style; From e3f24bdb8181a728fb5334d3285a25bdfe227108 Mon Sep 17 00:00:00 2001 From: natew Date: Mon, 9 Nov 2015 18:36:25 -0800 Subject: [PATCH 2/4] add options --- lib/index.js | 3 +-- lib/utils.js | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/index.js b/lib/index.js index b89bff9..4e14fae 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,4 @@ import { - sortObject, createClassName, createMarkup, seperateStyles, @@ -15,7 +14,7 @@ export default { return Object.keys( styles ).reduce( ( acc, key ) => { let { style, pseudos, mediaQueries } = seperateStyles( options, key, styles[key] ); - const className = createClassName(options, key, styles); + const className = createClassName(options, key, style); if (className === undefined) { acc[ key ] = ''; diff --git a/lib/utils.js b/lib/utils.js index 7d00014..f3fe2d9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -57,6 +57,8 @@ export function createClassName(options, tag, obj) { return selectors.join(' ') } + obj = sortObject(obj) + const hash = extendedToString( createHash( stringifyObject(obj) ), 62); return hash ? '_' + hash @@ -72,19 +74,19 @@ export function isEmpty(obj) { } const pseudos = { - ':active': 'active', - ':hover': 'hover', - ':focus': 'focus', - ':link': 'link', - ':visited': 'visited', - ':checked': 'checked', - ':disabled': 'disabled', - ':empty': 'empty', - ':invalid': 'invalid', + active: ':active', + hover: ':hover', + focus: ':focus', + link: ':link', + visited: ':visited', + checked: ':checked', + disabled: ':disabled', + empty: ':empty', + invalid: ':invalid', } export function isPseudo({ style, rule }) { - return pseudos[rule] && typeof style === 'object'; + return (rule.charAt(0) === ':' || pseudos[rule]) && typeof style === 'object'; } export function isMediaQuery({ style, rule }) { @@ -111,12 +113,12 @@ export function seperateStyles (options, tag, styles) { }; if ( isPseudo( content ) ) { - content.rule = pseudos[rule] // translate to :active + if (pseudos[rule]) content.rule = pseudos[rule] // translate to :active return handle(options, tag, 'pseudos', acc, content ); } if ( isMediaQuery( content ) ) { - const { style, pseudos } = seperateStyles( content.style ); + const { style, pseudos } = seperateStyles( options, tag, content.style ); return handle(options, tag, 'mediaQueries', acc, { rule, style }, pseudos ); } From 7520b6fe79e99179a9e8b16a234a25bf791c6e56 Mon Sep 17 00:00:00 2001 From: natew Date: Mon, 9 Nov 2015 18:48:59 -0800 Subject: [PATCH 3/4] add test --- lib/__tests__/lib.test.js | 15 +++++++++++++++ lib/index.js | 13 +++++++++++-- lib/utils.js | 2 -- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/__tests__/lib.test.js b/lib/__tests__/lib.test.js index 0523e41..d9cb476 100644 --- a/lib/__tests__/lib.test.js +++ b/lib/__tests__/lib.test.js @@ -153,6 +153,21 @@ describe('stilr', () => { } }); + it('handles custom names tags correctly', () => { + StyleSheet.create({ + mytag: { + color: 'tomato' + } + }, { + selectors: [ + { parent: 'SomeParent', child: tag => `.${tag}` } + ] + }); + + const css = StyleSheet.render(); + assert.equal(css, '.SomeParent .mytag{color:tomato;}') + }); + it('outputs pseudo classes correctly', () => { const hover = /(\._[\s\S]+)(:hover{)/g; diff --git a/lib/index.js b/lib/index.js index 4e14fae..c6c817a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,5 @@ import { + sortObject, createClassName, createMarkup, seperateStyles, @@ -8,13 +9,21 @@ import { let globalStylesheet = new Map(); export default { - create( styles, stylesheet = globalStylesheet, options ) { + create( styles, stylesheet = globalStylesheet ) { + let options + + if ( !(stylesheet instanceof Map) ) { + // options passed instead + options = stylesheet + stylesheet = globalStylesheet + } + if ( !(stylesheet instanceof Map) ) throw new Error(`${ stylesheet } should be a Map`); return Object.keys( styles ).reduce( ( acc, key ) => { let { style, pseudos, mediaQueries } = seperateStyles( options, key, styles[key] ); - const className = createClassName(options, key, style); + const className = createClassName(options, key, sortObject(style)); if (className === undefined) { acc[ key ] = ''; diff --git a/lib/utils.js b/lib/utils.js index f3fe2d9..a68b5e5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -57,8 +57,6 @@ export function createClassName(options, tag, obj) { return selectors.join(' ') } - obj = sortObject(obj) - const hash = extendedToString( createHash( stringifyObject(obj) ), 62); return hash ? '_' + hash From d2193f76e5358eb7e72dfb11e569511510935e38 Mon Sep 17 00:00:00 2001 From: natew Date: Mon, 9 Nov 2015 18:57:17 -0800 Subject: [PATCH 4/4] fix tags --- lib/__tests__/lib.test.js | 19 +++++++++++++------ lib/index.js | 12 +++++++++--- lib/utils.js | 9 ++------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/__tests__/lib.test.js b/lib/__tests__/lib.test.js index d9cb476..2196aff 100644 --- a/lib/__tests__/lib.test.js +++ b/lib/__tests__/lib.test.js @@ -155,19 +155,26 @@ describe('stilr', () => { it('handles custom names tags correctly', () => { StyleSheet.create({ - mytag: { - color: 'tomato' - } + mytag: { color: 'tomato' } }, { - selectors: [ - { parent: 'SomeParent', child: tag => `.${tag}` } - ] + selector: tag => `.SomeParent .${tag}` }); const css = StyleSheet.render(); assert.equal(css, '.SomeParent .mytag{color:tomato;}') }); + it('handles multiple custom names tags correctly', () => { + StyleSheet.create({ + tag: { color: 'tomato' } + }, { + selector: tag => `.One .${tag}, .Two .${tag}` + }); + + const css = StyleSheet.render(); + assert.equal(css, '.One .tag, .Two .tag{color:tomato;}') + }); + it('outputs pseudo classes correctly', () => { const hover = /(\._[\s\S]+)(:hover{)/g; diff --git a/lib/index.js b/lib/index.js index c6c817a..a7c010b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -16,6 +16,9 @@ export default { // options passed instead options = stylesheet stylesheet = globalStylesheet + + if (options.selector) + stylesheet.customTags = true } if ( !(stylesheet instanceof Map) ) throw new Error(`${ stylesheet } should be a Map`); @@ -36,7 +39,7 @@ export default { if ( pseudos.length ) { pseudos.map( selector => { delete style[selector]; - const pseudoClassName = `${className}${selector}`; + const pseudoClassName = `.${className}${selector}`; if ( stylesheet.has( pseudoClassName ) ) return false; @@ -85,6 +88,7 @@ export default { } acc[ key ] = className; + return acc; }, {}); }, @@ -109,9 +113,11 @@ export default { } const markup = createMarkup( styles ); + const prefix = stylesheet.customTags ? '' : '.' + css += options.pretty - ? `.${ className } {\n${ markup.split(';').join(';\n')}}\n` - : `.${ className }{${ markup }}`; + ? `${prefix}${ className } {\n${ markup.split(';').join(';\n')}}\n` + : `${prefix}${ className }{${ markup }}`; } return css + mediaQueries; diff --git a/lib/utils.js b/lib/utils.js index a68b5e5..e7dc469 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -48,13 +48,8 @@ export function extendedToString(num, base) { } export function createClassName(options, tag, obj) { - if (options && options.selectors) { - let selectors = options.selectors.map(({ parent, child }) => { - child = child(tag) - return parent ? `${parent} ${child}` : child - }) - - return selectors.join(' ') + if (options && options.selector) { + return options.selector(tag) } const hash = extendedToString( createHash( stringifyObject(obj) ), 62);