From 8497d107bd9ad63c43fc9374b01107337fe2d90e Mon Sep 17 00:00:00 2001 From: estrattonbailey Date: Tue, 23 Mar 2021 17:33:58 -0500 Subject: [PATCH] feat(named breakpoints): adds breakpoint object syntax specify breakpoints by index using object syntax --- index.js | 23 ++++++++++++-- test/hypostyle.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 14ccc85..6e58424 100644 --- a/index.js +++ b/index.js @@ -17,8 +17,20 @@ function parse (obj, theme) { const rawValue = obj[prop] if (typeof rawValue === 'object' && !Array.isArray(rawValue)) { - styles[prop] = style(rawValue, theme) - continue + const rawValueKeys = Object.keys(rawValue) + + if (/^\d/.test(rawValueKeys[0])) { + const newRawValue = [] + + for (const key of rawValueKeys) { + newRawValue[key] = rawValue[key] + } + + obj[prop] = newRawValue + } else { + styles[prop] = style(rawValue, theme) + continue // continue main loop + } } // just make all values resposive-ready @@ -29,15 +41,22 @@ function parse (obj, theme) { const token = tokens ? tokens[value] || value : value const unitValue = unit ? unit(token) : token + // drop undefined values, all others pass through + if (unitValue === undefined) continue + let s = styles const breakpoint = theme.breakpoints[i - 1] if (breakpoint) { const media = `@media (min-width: ${breakpoint})` + // drop down a level (into breakpoint) s = styles[media] = styles[media] || {} } + // if someone passes a breakpoint that doesn't exist + if (!breakpoint && i > 0) continue + for (const property of properties) { s[property] = unitValue } diff --git a/test/hypostyle.js b/test/hypostyle.js index 9c2019b..8769061 100644 --- a/test/hypostyle.js +++ b/test/hypostyle.js @@ -146,6 +146,31 @@ export default (test, assert) => { assert(styles['@media (min-width: 800px)'].color === 'green') }) + test('too many breakpoints', () => { + const { style } = hypostyle({ + breakpoints: ['400px', '800px'], + shorthands + }) + const styles = style({ + c: ['blue', 'red', 'green', 'tomato'] + }) + + assert(styles.color === 'blue') // could otherwise be tomato + }) + + test('named breakpoints', () => { + const { style } = hypostyle({ + breakpoints: ['400px', '800px', '1200px'], + shorthands + }) + const styles = style({ + c: { 0: 'blue', 2: 'red' } + }) + + assert(styles.color === 'blue') + assert(styles['@media (min-width: 800px)'].color === 'red') + }) + test('breakpoints to sheet', () => { const { css, flush } = hypostyle({ breakpoints: ['400px', '800px'], @@ -253,4 +278,59 @@ export default (test, assert) => { assert(sheet.includes('font-size:3rem')) }) + + test('nested elements', () => { + const { css, flush } = hypostyle(defaults) + + const cn = css({ + div: { + color: 'tomato' + } + }) + const sheet = flush() + const selector = new RegExp(`.${cn.trim()} div`) + + assert(selector.test(sheet) === true) + }) + + test('pseudo selectors', () => { + const { css, flush } = hypostyle(defaults) + + const cn = css({ + '&:hover': { + color: 'tomato' + } + }) + const sheet = flush() + const selector = new RegExp(`.${cn.trim()}:hover`) + + assert(selector.test(sheet) === true) + }) + + test('pseudo selectors w/ nested elements', () => { + const { css, flush } = hypostyle(defaults) + + const cn = css({ + '&:hover div': { + color: 'tomato' + } + }) + const sheet = flush() + const selector = new RegExp(`.${cn.trim()}:hover div`) + + assert(selector.test(sheet) === true) + }) + + test('media queries', () => { + const { css, flush } = hypostyle(defaults) + + css({ + '@media (min-width: 567px)': { + color: 'tomato' + } + }) + const sheet = flush() + + assert(/@media\s\(min-width: 567px\)/.test(sheet) === true) + }) }