Skip to content

Commit

Permalink
feat: initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
kirkov committed Jan 20, 2018
1 parent 079f93b commit c2b4006
Show file tree
Hide file tree
Showing 17 changed files with 5,387 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
indent_size = 2
indent_style = space
end_of_line = lf
insert_final_newline = false
trim_trailing_whitespace = true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
22 changes: 22 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
language: node_js

cache:
yarn: true
directories:
- ~/.npm

notifications:
email: false

node_js:
- '8'

script:
- yarn lint
- yarn test

deploy:
provider: script
skip_cleanup: true
script:
- npm run semantic-release
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Breakbox
Responsive React container components.
56 changes: 56 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "breakbox",
"description": "Responsive React container components.",
"main": "dist/index.js",
"source": "src/index.js",
"scripts": {
"dist": "babel src --out-dir dist --ignore *.test.js",
"lint": "standard",
"test": "jest",
"test:watch": "jest --watch",
"semantic-release": "semantic-release"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.0.0-beta.38",
"@babel/core": "^7.0.0-beta.38",
"@babel/preset-env": "^7.0.0-beta.38",
"@babel/preset-react": "^7.0.0-beta.38",
"@babel/preset-stage-3": "^7.0.0-beta.38",
"babel-core": "^7.0.0-0",
"babel-jest": "^22.1.0",
"jest": "^22.1.4",
"prop-types": "^15.6.0",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react-test-renderer": "^16.1.1",
"semantic-release": "^12.2.2",
"standard": "^10.0.3"
},
"dependencies": {
"cxs": "^6.1.0"
},
"peerDependencies": {
"prop-types": "^15.5.7",
"react": "^15.3.0 || ^16.0.0",
"react-dom": "^15.3.0 || ^16.0.0"
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-stage-3"
],
"plugins": []
},
"jest": {
"roots": [
"src"
]
},
"repository": {
"type": "git",
"url": "https://github.com/kirkov/breakbox.git"
}
}
169 changes: 169 additions & 0 deletions src/__snapshots__/breakbox.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`can provide custom breakpoints: uses custom breakpoints 1`] = `
<div
className=" x0 x1 x2"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{width:50px}@media (min-width: 100px){.x1{width:150px}}@media (min-width: 200px){.x2{width:250px}}",
}
}
/>
</div>
`;

exports[`can provide custom spaces: handle unknowns space 1`] = `
<div
className=" x0 x1 x2"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{padding-right:10px}@media (min-width: 600px){.x1{padding-right:20px}}@media (min-width: 900px){.x2{padding-right:3px}}",
}
}
/>
</div>
`;

exports[`can provide custom spaces: looks up the custom space values 1`] = `
<div
className=" x0 x1 x2"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{padding-right:10px}@media (min-width: 600px){.x1{padding-right:20px}}@media (min-width: 900px){.x2{padding-right:30px}}",
}
}
/>
</div>
`;

exports[`can provide custom spaces: uses custom spaces 1`] = `
<div
className=" x0 x1 x2"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{margin-right:50}@media (min-width: 600px){.x1{margin-right:150}}@media (min-width: 900px){.x2{margin-right:250}}",
}
}
/>
</div>
`;

exports[`handle single values: null value 1`] = `
<div
className=" "
>
<style
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
/>
</div>
`;

exports[`handle single values: single value 1`] = `
<div
className=" x0"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{flex-direction:row}",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips empty 1`] = `
<div
className=" "
>
<style
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips empty string 1`] = `
<div
className=" "
>
<style
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips middle value 1`] = `
<div
className=" x0 x1"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{flex-direction:row}@media (min-width: 900px){.x1{flex-direction:column}}",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips multiple values 1`] = `
<div
className=" x0 x1"
>
<style
dangerouslySetInnerHTML={
Object {
"__html": ".x0{flex-direction:row}@media (min-width: 900px){.x1{flex-direction:column}}",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips null 1`] = `
<div
className=" "
>
<style
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
/>
</div>
`;

exports[`skips breakpoints: skips undefined 1`] = `
<div
className=" "
>
<style
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
/>
</div>
`;
87 changes: 87 additions & 0 deletions src/breakbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react'
import cxs from 'cxs'
import defaultConfig from './config'
import contextTypes from './context-types'

const resolveValue = (spaces, value) => {
if (typeof value !== 'number') return value

return value <= spaces.length
? spaces[value - 1]
: value + 'px'
}

const getStyles = (props, config) => {
const { spaces } = config

// Add '0' value for default value (without a media query)
const breakpoints = [0, ...config.breakpoints]
const stylesPerBreakpoint = breakpoints.map(b => [])

Object.entries(props).forEach(([prop, values]) => {
if (Array.isArray(values)) {
for (let i = 0; i < values.length; i++) {
const value = values[i]
if (value === null || value === undefined) continue

const resolvedValue = resolveValue(spaces, value)
stylesPerBreakpoint[i].push([prop, resolvedValue])
}
} else if (values !== null && values !== undefined) {
stylesPerBreakpoint[0].push([prop, resolveValue(spaces, values)])
}
})

const styles = stylesPerBreakpoint.reduce((result, declarations, index) => {
// const media = stylesPerBreakpoint.length-1 !== index
// ? `@media (min-width: ${breakpoints[(stylesPerBreakpoint.length-1) - index]})`
// : null

const media = index !== 0
? `@media (min-width: ${breakpoints[index]})`
: null

const declarationsObj = declarations.reduce((res, declaration) => {
const [property, value] = declaration
res[property] = value
return res
}, {})

if (media === null) result = { ...result, ...declarationsObj }
else result[media] = declarationsObj

return result
}, {})

Object.keys(styles).forEach(key => (Object.keys(styles[key]).length === 0) && delete styles[key])

return styles
}

export const breakbox = (containerStyles = {}, component = 'div') => {
const BreakboxComponent = ({className, children, ...otherProps}, context) => {
const config = Object.assign({}, defaultConfig, context.breakbox)
const styles = getStyles(Object.assign(otherProps, containerStyles), config)
const stylesClassName = cxs(styles)

// used for testing
let debug = null
if (process.env.NODE_ENV === 'test') {
debug = <style key='css' dangerouslySetInnerHTML={{ __html: cxs.css() }} />
}

return React.createElement(
component,
{
className: [className, stylesClassName].join(' ')
},
[ children, debug ]
)
}

BreakboxComponent.contextTypes = contextTypes

return BreakboxComponent
}

export const resetStyles = () => cxs.reset()
Loading

0 comments on commit c2b4006

Please sign in to comment.