diff --git a/lib/__tests__/lib.test.js b/lib/__tests__/lib.test.js index 0523e41..2196aff 100644 --- a/lib/__tests__/lib.test.js +++ b/lib/__tests__/lib.test.js @@ -153,6 +153,28 @@ describe('stilr', () => { } }); + it('handles custom names tags correctly', () => { + StyleSheet.create({ + mytag: { color: 'tomato' } + }, { + 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/__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..a7c010b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10,12 +10,23 @@ let globalStylesheet = new Map(); export default { create( styles, stylesheet = globalStylesheet ) { + let options + + if ( !(stylesheet instanceof Map) ) { + // 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`); 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, sortObject(style)); if (className === undefined) { acc[ key ] = ''; @@ -28,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; @@ -77,6 +88,7 @@ export default { } acc[ key ] = className; + return acc; }, {}); }, @@ -101,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 38b9dda..e7dc469 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -47,7 +47,11 @@ export function extendedToString(num, base) { return (base < 11) ? parseInt(conversion) : conversion; } -export function createClassName(obj) { +export function createClassName(options, tag, obj) { + if (options && options.selector) { + return options.selector(tag) + } + const hash = extendedToString( createHash( stringifyObject(obj) ), 62); return hash ? '_' + hash @@ -62,16 +66,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 (rule.charAt(0) === ':' || 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 +98,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 +106,13 @@ export function seperateStyles (styles) { }; if ( isPseudo( content ) ) { - return handle('pseudos', acc, content ); + 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 ); - return handle('mediaQueries', acc, { rule, style }, pseudos ); + const { style, pseudos } = seperateStyles( options, tag, content.style ); + return handle(options, tag, 'mediaQueries', acc, { rule, style }, pseudos ); } acc.style[rule] = content.style;