├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── examples ├── ChildSpans.cjsx ├── ComplexResponsiveLayout.cjsx ├── Controls.cjsx ├── Intro.cjsx ├── PrePostSquish.cjsx ├── Router.cjsx ├── ThreeColumn.cjsx ├── TwoColumn.cjsx ├── index.cjsx └── index.html ├── package.json ├── src ├── components │ ├── Breakpoint.cjsx │ ├── Container.cjsx │ ├── Grid.cjsx │ └── Span.cjsx ├── index.cjsx └── utils │ └── SpanCalculate.coffee ├── test └── calc.coffee ├── webpack.config.js └── webpack.config.production.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | susy-test/ 30 | examples/bundle.js 31 | dist/ 32 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | susy-test/ 30 | examples/bundle.js 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.10" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kyle Mathews 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = ./node_modules/.bin 2 | 3 | release-patch: 4 | @$(call release,patch) 5 | 6 | release-minor: 7 | @$(call release,minor) 8 | 9 | release-major: 10 | @$(call release,major) 11 | 12 | build: 13 | @$(BIN)/cjsx -cb -o dist/ src/ 14 | @$(BIN)/webpack 15 | 16 | watch: 17 | @$(BIN)/webpack-dev-server -w 18 | 19 | publish: 20 | git push --tags origin HEAD:master 21 | @$(BIN)/cjsx -cb -o dist/ src/ 22 | npm publish 23 | 24 | publish-gh-pages: 25 | git checkout gh-pages 26 | git merge master 27 | @$(BIN)/webpack --config webpack.config.production.js 28 | cp examples/* . 29 | git add --all . 30 | git commit -m "New release" 31 | git push origin gh-pages 32 | git checkout master 33 | 34 | define release 35 | npm version $(1) 36 | endef 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build 2 | Status](https://img.shields.io/travis/KyleAMathews/react-responsive-grid/master.svg?style=flat-square)](http://travis-ci.org/KyleAMathews/react-responsive-grid) 3 | 4 | # react-responsive-grid 5 | Power tools for building responsive layouts with React. 6 | 7 | WIP, porting best ideas from [Susy](http://susy.oddbird.net/) to a React-friendly and CSS-independent format. 8 | 9 | ### Susy porting progress 10 | #### Container 11 | - [x] Basic fluid container 12 | - [ ] static 13 | - [ ] non-centered layouts 14 | - [ ] container positions (left, center (default), right, length (left 15 | and right)) 16 | 17 | #### Breakpoint 18 | - [x] Basic component width breakpoints (note this is different than a 19 | media query breakpoint) 20 | - [ ] Media query breakpoints 21 | 22 | #### Columns 23 | - [x] set number of columns 24 | - [ ] list — create asymmetrical grids. List the size of each column 25 | relative to other columns where 1 is a single column-unit. (1,2) would 26 | create a 2-column grid where the second column being twice the width of 27 | the first. 28 | 29 | #### Gutter options 30 | - [x] margin-based 31 | - [ ] padding-based 32 | - [ ] explicit gutter width 33 | 34 | #### Gutter positions 35 | - [ ] before 36 | - [x] after 37 | - [ ] inside 38 | - [ ] inside-static 39 | - [ ] split 40 | 41 | #### Span 42 | - [x] Set # of columns 43 | - [ ] Set arbitrary width 44 | - [x] Remove last gutter by "last" prop 45 | - [ ] Remove first gutter by "first" prop 46 | - [x] Support nested spans 47 | - [x] Set location of span using "at" prop 48 | - [ ] Span external gutters (in addition to internal gutters) 49 | - [x] "break" prop — start new row by clearing previous spans 50 | - [ ] No gutters option 51 | - [ ] "full" prop — shortcut for a span to fill its entire context 52 | - [x] "pre" prop — add margin before a span 53 | - [x] "post" prop — add margin after a span 54 | - [x] "squish" prop — shortcut for adding pre and post margins to the 55 | same span 56 | - [ ] "pull" prop — add negative margin before a span pulling it against 57 | the direction of flow 58 | - [ ] "prefix" prop — add padding before a span 59 | - [ ] "suffix" prop — add padding after a span 60 | - [ ] "pad" prop — add padding before and after a span 61 | - [ ] "bleed" prop — Apply negative margins and equal positive padding 62 | so that span borders and backgrounds "bleed" outside of their 63 | containers 64 | - [ ] "bleed-x" prop — a shortcut for applying only left and right 65 | (horixontal) bleed 66 | - [ ] "bleed-y" prop — a shortcut for applying only top and bottom 67 | (vertical) bleed 68 | 69 | #### Debuggin 70 | - [ ] Show grid 71 | -------------------------------------------------------------------------------- /examples/ChildSpans.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | {Container, Grid, Breakpoint, Span} = require '../src/index' 3 | 4 | module.exports = React.createClass 5 | render: -> 6 |
7 |

Child spans

8 |

9 | Code 10 |

11 | 12 | 13 |
Hi
14 |
15 | 16 | 17 |
18 | I'm a child span with 1 column 19 |
20 |
21 | 22 |
23 | I'm a child span with 3 columns 24 |
25 |
26 | 27 |
28 | I'm a child span with 4 columns 29 |
30 |
31 | 32 |
33 | I'm a child span with 3 columns 34 |
35 |
36 | 37 |
38 | I'm a child span with 1 column 39 |
40 |
41 |
42 | 43 |
Hi
44 |
45 | 46 |
Hi
47 |
48 |
49 |
50 | -------------------------------------------------------------------------------- /examples/ComplexResponsiveLayout.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | {Container, Grid, Breakpoint, Span} = require '../src/index' 3 | 4 | purpleStyle = 5 | border: '2px solid purple' 6 | color: 'purple' 7 | height: '10rem' 8 | fontSize: '2rem' 9 | lineHeight: '10rem' 10 | marginBottom: '1rem' 11 | textAlign: 'center' 12 | 13 | module.exports = React.createClass 14 | render: -> 15 |
16 |

More complex layout taken from http://www.zell-weekeat.com/smarter-layouts-with-susy/

17 |

Shrink screen to see simplified layout for small devices

18 |

19 | Code 20 |

21 | 22 | 23 | 24 |
1
25 |
26 | 27 |
2
28 |
29 | 30 | 31 |
3
32 |
33 | 34 |
4
35 |
36 | 37 |
5
38 |
39 | 40 | 41 |
6
42 |
43 | 44 |
7
45 |
46 | 47 | 48 |
8
49 |
50 | 51 |
9
52 |
53 | 54 |
10
55 |
56 |
57 | 58 | 59 | 60 |
1
61 |
62 | 63 | 64 |
2
65 |
66 | 67 |
3
68 |
69 | 70 | 71 |
4
72 |
73 | 74 |
5
75 |
76 | 77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /examples/Controls.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | {Link} = require 'react-router' 3 | 4 | module.exports = React.createClass 5 | render: -> 6 | 14 | -------------------------------------------------------------------------------- /examples/Intro.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | 3 | module.exports = React.createClass 4 | render: -> 5 |
6 |

React Responsive Grid

7 |

This is a long introductionary paragraph

8 |
9 | 10 | -------------------------------------------------------------------------------- /examples/PrePostSquish.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | {Container, Grid, Breakpoint, Span} = require '../src/index' 3 | 4 | purpleStyle = 5 | border: '2px solid purple' 6 | color: 'purple' 7 | height: '10rem' 8 | fontSize: '1rem' 9 | lineHeight: '10rem' 10 | marginBottom: '1rem' 11 | textAlign: 'center' 12 | 13 | module.exports = React.createClass 14 | render: -> 15 |
16 |

Demo squish, post, pre

17 |

18 | Code 19 |

20 |

Squish

21 | 22 | {""} 23 | {""} 24 | {""} 25 | {""} 26 | {""} 27 | 28 |

Pre

29 | 30 | {""} 31 | {""} 32 | {""} 33 | {""} 34 | {""} 35 | 36 |

Post

37 | 38 | {""} 39 | {""} 40 | {""} 41 | {""} 42 | {""} 43 | 44 |

Using them together

45 | 46 | {""} 47 | {""} 48 | {""} 49 | {" 50 | {" 51 | {" 52 | {" 53 | {""} 54 | {""} 55 | {""} 56 | 57 |
58 | 59 | -------------------------------------------------------------------------------- /examples/Router.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | {render} = require 'react-dom' 3 | {browserHistory, Router, Route, IndexRoute} = require 'react-router' 4 | {Container, Grid, Breakpoint, Span} = require '../src/index' 5 | 6 | Typography = require 'typography' 7 | typography = Typography() 8 | {injectStyles, rhythm} = typography 9 | injectStyles() 10 | 11 | Controls = require './Controls' 12 | Intro = require './Intro' 13 | 14 | App = React.createClass 15 | render: -> 16 |
17 |
26 | 27 |
28 | 33 | {@props.children} 34 | 35 |
36 | 37 | routes = ( 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ) 47 | 48 | render(, document.getElementById("mount-point")) 49 | -------------------------------------------------------------------------------- /examples/ThreeColumn.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | faker = require 'faker' 3 | {Container, Grid, Breakpoint, Span} = require '../src/index' 4 | 5 | module.exports = React.createClass 6 | render: -> 7 |
8 |

Simple three column layout

9 |

10 | Code 11 |

12 | 13 | 14 |
Left column
19 |
20 | 21 |
{faker.lorem.paragraphs(6)}
26 |
27 | 28 |
Right column
33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /examples/TwoColumn.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | faker = require 'faker' 3 | {Container, Grid, Breakpoint, Span} = require '../src/index' 4 | 5 | module.exports = React.createClass 6 | render: -> 7 |
8 |

Responsive two column layout

9 |

10 | Code 11 |

12 | 13 | 14 | 15 |
{faker.lorem.paragraphs(6)}
20 |
21 | 22 |
Right column
27 |
28 |
29 | 30 |
Right column
35 |
{faker.lorem.paragraphs(6)}
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /examples/index.cjsx: -------------------------------------------------------------------------------- 1 | React = require('react') 2 | Examples = require './examples' 3 | 4 | React.render(, document.body) 5 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 4 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-responsive-grid", 3 | "description": "Power tools for responsive layouts with React", 4 | "version": "0.3.4", 5 | "author": "Kyle Mathews ", 6 | "bugs": { 7 | "url": "https://github.com/KyleAMathews/react-responsive-grid/issues" 8 | }, 9 | "dependencies": { 10 | "object-assign": "^4.0.1", 11 | "react-component-width-mixin": "^2.0.0", 12 | "react-page-width": "^1.0.1" 13 | }, 14 | "devDependencies": { 15 | "chai": "^3.4.0", 16 | "cjsx-loader": "^3.0.0", 17 | "coffee-loader": "^0.7.2", 18 | "coffee-react": "^5.0.0", 19 | "coffee-script": "^1.9.2", 20 | "css-loader": "^0.23.1", 21 | "faker": "^3.1.0", 22 | "gulp": "^3.8.11", 23 | "mocha": "^2.2.5", 24 | "mocha-unfunk-reporter": "^0.4.0", 25 | "node-libs-browser": "^1.0.0", 26 | "pre-commit": "^1.0.7", 27 | "react": "^15.0.1", 28 | "react-dom": "^15.0.1", 29 | "react-hot-loader": "^1.2.7", 30 | "react-router": "^2.2.4", 31 | "style-loader": "^0.13.0", 32 | "typography": "^0.7.0", 33 | "underscore": "^1.8.3", 34 | "webpack": "^1.9.7", 35 | "webpack-dev-server": "^1.8.2" 36 | }, 37 | "directories": { 38 | "example": "examples" 39 | }, 40 | "homepage": "https://github.com/KyleAMathews/react-responsive-grid", 41 | "keywords": [ 42 | "960", 43 | "fluid", 44 | "grid", 45 | "layout", 46 | "react", 47 | "react-component", 48 | "responsive", 49 | "rwd", 50 | "semantic", 51 | "susy" 52 | ], 53 | "license": "MIT", 54 | "main": "dist/index.js", 55 | "peerDependencies": { 56 | "react": ">=0.13.0" 57 | }, 58 | "repository": { 59 | "type": "git", 60 | "url": "https://github.com/KyleAMathews/react-responsive-grid.git" 61 | }, 62 | "scripts": { 63 | "test-watch": "NODE_ENV=test node_modules/.bin/mocha -w --recursive --compilers coffee:coffee-script/register -R mocha-unfunk-reporter", 64 | "test": "NODE_ENV=test node_modules/.bin/mocha --recursive --compilers coffee:coffee-script/register -R mocha-unfunk-reporter" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/Breakpoint.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | componentWidthMixin = require 'react-component-width-mixin' 3 | PageWidthMixin = require 'react-page-width' 4 | objectAssign = require 'object-assign' 5 | 6 | ComponentWidthComponent = React.createClass 7 | displayName: "Breakpoint" 8 | 9 | mixins: [componentWidthMixin] 10 | 11 | propTypes: 12 | minWidth: React.PropTypes.number 13 | maxWidth: React.PropTypes.number 14 | 15 | getDefaultProps: -> 16 | { 17 | minWidth: 0 18 | maxWidth: 1000000000000000000000 19 | } 20 | 21 | renderChildren: -> 22 | React.Children.map(@props.children, (child) => 23 | if child?.type?.displayName is "Span" 24 | React.cloneElement(child, { 25 | context: @props.context 26 | }) 27 | else 28 | child 29 | ) 30 | 31 | render: -> 32 | props = objectAssign {}, @props 33 | delete props.maxWidth 34 | delete props.minWidth 35 | delete props.widthMethod 36 | 37 | if @state.componentWidth 38 | if @props.minWidth <= @state.componentWidth < @props.maxWidth 39 |
{@renderChildren()}
40 | else 41 | return
42 | else 43 | return
44 | 45 | PageWidthComponent = React.createClass 46 | displayName: "Breakpoint" 47 | 48 | mixins: [PageWidthMixin] 49 | 50 | propTypes: 51 | minWidth: React.PropTypes.number 52 | maxWidth: React.PropTypes.number 53 | 54 | getDefaultProps: -> 55 | { 56 | minWidth: 0 57 | maxWidth: 1000000000000000000000 58 | } 59 | 60 | renderChildren: -> 61 | React.Children.map(@props.children, (child) => 62 | if child.type?.displayName is "Span" 63 | React.cloneElement(child, { 64 | context: @props.context 65 | }) 66 | else 67 | child 68 | ) 69 | 70 | render: -> 71 | props = objectAssign {}, @props 72 | delete props.maxWidth 73 | delete props.minWidth 74 | delete props.widthMethod 75 | 76 | if @state.pageWidth 77 | if @props.minWidth <= @state.pageWidth < @props.maxWidth 78 |
{@renderChildren()}
79 | else 80 | return
81 | else 82 | return
83 | 84 | module.exports = React.createClass 85 | displayName: 'Breakpoint' 86 | 87 | propTypes: 88 | widthMethod: React.PropTypes.string.isRequired 89 | minWidth: React.PropTypes.number 90 | maxWidth: React.PropTypes.number 91 | 92 | getDefaultProps: -> 93 | widthMethod: 'pageWidth' 94 | 95 | render: -> 96 | if @props.widthMethod is "pageWidth" 97 | 98 | else if @props.widthMethod is "componentWidth" 99 | 100 | -------------------------------------------------------------------------------- /src/components/Container.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | objectAssign = require('object-assign') 3 | 4 | module.exports = React.createClass 5 | displayName: "Container" 6 | 7 | render: -> 8 | defaultStyles = 9 | maxWidth: '960px' 10 | marginLeft: 'auto' 11 | marginRight: 'auto' 12 | 13 | styles = objectAssign defaultStyles, @props.style 14 | children = @props.children 15 | 16 | props = objectAssign {}, @props 17 | delete props.children 18 | delete props.style 19 | 20 |
21 | {children} 22 | {' '} 23 |
24 | -------------------------------------------------------------------------------- /src/components/Grid.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | objectAssign = require('object-assign') 3 | 4 | module.exports = React.createClass 5 | displayName: "Grid" 6 | 7 | propTypes: 8 | columns: React.PropTypes.number 9 | gutterRatio: React.PropTypes.number 10 | 11 | getDefaultProps: -> 12 | { 13 | columns: 12 14 | gutterRatio: 1/4 15 | } 16 | 17 | renderChildren: -> 18 | React.Children.map(@props.children, (child) => 19 | if child.type?.displayName in ["Breakpoint", "Span"] 20 | React.cloneElement(child, { 21 | context: 22 | columns: @props.columns 23 | gutterRatio: @props.gutterRatio 24 | }) 25 | else 26 | child 27 | ) 28 | 29 | render: -> 30 | props = objectAssign {}, @props 31 | delete props.gutterRatio 32 | delete props.columns 33 | 34 |
35 | {@renderChildren()} 36 | {' '} 37 |
38 | -------------------------------------------------------------------------------- /src/components/Span.cjsx: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | objectAssign = require('object-assign') 3 | 4 | spanCalculate = require '../utils/SpanCalculate' 5 | 6 | module.exports = React.createClass 7 | displayName: "Span" 8 | 9 | propTypes: 10 | context: React.PropTypes.object 11 | columns: React.PropTypes.number 12 | at: React.PropTypes.number 13 | pre: React.PropTypes.number 14 | post: React.PropTypes.number 15 | squish: React.PropTypes.number 16 | last: React.PropTypes.bool 17 | break: React.PropTypes.bool 18 | 19 | getDefaultProps: -> 20 | at: 0 21 | pre: 0 22 | post: 0 23 | squish: 0 24 | last: false 25 | first: false 26 | break: false 27 | 28 | renderChildren: -> 29 | React.Children.map(@props.children, (child) => 30 | if child?.type?.displayName is "Span" 31 | React.cloneElement(child, { 32 | # Sub-spans need to know # of columns of parent. 33 | context: 34 | columns: @props.columns 35 | gutterRatio: @props.context.gutterRatio 36 | }) 37 | else 38 | child 39 | ) 40 | 41 | render: -> 42 | style = spanCalculate({ 43 | contextColumns: @props.context.columns 44 | gutterRatio: @props.context.gutterRatio 45 | columns: @props.columns 46 | at: @props.at 47 | pre: @props.pre 48 | post: @props.post 49 | squish: @props.squish 50 | last: @props.last 51 | break: @props.break 52 | }) 53 | 54 | style = objectAssign style, @props.style 55 | 56 | props = objectAssign {}, @props, {"style": style} 57 | delete props.at 58 | delete props.break 59 | delete props.columns 60 | delete props.context 61 | delete props.first 62 | delete props.last 63 | delete props.post 64 | delete props.pre 65 | delete props.squish 66 | delete props.style 67 | 68 |
69 | {@renderChildren()} 70 | {' '} 71 |
72 | -------------------------------------------------------------------------------- /src/index.cjsx: -------------------------------------------------------------------------------- 1 | exports.Container = require './components/Container' 2 | exports.Grid = require './components/Grid' 3 | exports.Breakpoint = require './components/Breakpoint' 4 | exports.Span = require './components/Span' 5 | -------------------------------------------------------------------------------- /src/utils/SpanCalculate.coffee: -------------------------------------------------------------------------------- 1 | objectAssign = require('object-assign') 2 | 3 | module.exports = (options) -> 4 | defaults = 5 | columns: 3 6 | at: 0 7 | pre: 0 8 | post: 0 9 | squish: 0 10 | contextColumns: 12 11 | gutterRatio: 1/4 12 | first: false 13 | last: false 14 | 15 | ops = objectAssign defaults, options 16 | 17 | # Calculate the width of one column. 18 | n = 100/(ops.contextColumns + ((ops.contextColumns-1) * ops.gutterRatio)) 19 | 20 | # Calculate the width of a gutter. 21 | gutterWidth = ops.gutterRatio * n 22 | 23 | # Function to calculate width of a span. 24 | calcSpanWidth = (numColumns) -> 25 | n*numColumns + gutterWidth*(numColumns-1) 26 | 27 | calcSpacing = (numColumns) -> 28 | if numColumns is 0 29 | return 0 30 | else 31 | calcSpanWidth(numColumns) + gutterWidth 32 | 33 | # width 34 | width = calcSpanWidth(ops.columns) 35 | 36 | # marginLeft 37 | if ops.at is 0 and ops.pre is 0 and ops.squish is 0 38 | marginLeft = 0 39 | else 40 | marginLeft = 41 | calcSpacing(ops.at) + 42 | calcSpacing(ops.pre) + 43 | calcSpacing(ops.squish) 44 | 45 | # marginRight 46 | if ops.last and ops.post is 0 and ops.squish is 0 47 | marginRight = 0 48 | else if ops.post isnt 0 or ops.squish isnt 0 49 | marginRight = 50 | calcSpacing(ops.post) + 51 | calcSpacing(ops.squish) 52 | 53 | unless ops.last 54 | marginRight = marginRight + gutterWidth 55 | 56 | else 57 | marginRight = gutterWidth 58 | 59 | # float 60 | if ops.last 61 | float = "right" 62 | else 63 | float = "left" 64 | 65 | # Add % 66 | width = width + "%" 67 | marginLeft = marginLeft + "%" 68 | marginRight = marginRight + "%" 69 | 70 | return { 71 | float: float 72 | marginLeft: marginLeft 73 | marginRight: marginRight 74 | width: width 75 | clear: if ops.break then 'both' else 'none' 76 | } 77 | -------------------------------------------------------------------------------- /test/calc.coffee: -------------------------------------------------------------------------------- 1 | chai = require 'chai' 2 | expect = chai.expect 3 | _ = require 'underscore' 4 | 5 | spanCalculate = require '../src/utils/SpanCalculate' 6 | 7 | describe 'grid calculate module', -> 8 | it 'should exist', -> 9 | expect(spanCalculate).to.exist 10 | 11 | it 'should return an object', -> 12 | expect(spanCalculate()).to.be.instanceof(Object) 13 | 14 | it 'should return an object that includes style keys', -> 15 | expect(_.keys(spanCalculate())).to.deep.equal([ 16 | 'float' 17 | 'marginLeft' 18 | 'marginRight' 19 | 'width' 20 | 'clear' 21 | ]) 22 | 23 | it 'should set marginLeft if at isn\'t 0', -> 24 | styles = spanCalculate({at: 1, columns: 3}) 25 | noAtstyles = spanCalculate({at: 0, columns: 3}) 26 | 27 | expect(styles.marginLeft).to.equal("8.47457627118644%") 28 | expect(noAtstyles.marginLeft).to.equal("0%") 29 | expect(styles.width).to.equal(noAtstyles.width) 30 | 31 | it 'should set marginRight to one gutter width by default', -> 32 | styles = spanCalculate({columns: 3}) 33 | 34 | expect(styles.marginRight).to.equal("1.694915254237288%") 35 | 36 | it 'should remove marginRight if last prop', -> 37 | styles = spanCalculate({last: true}) 38 | expect(styles.marginRight).to.equal("0%") 39 | 40 | it 'should float left by default', -> 41 | styles = spanCalculate() 42 | expect(styles.float).to.equal("left") 43 | 44 | it 'should float right if last prop', -> 45 | styles = spanCalculate({last: true}) 46 | expect(styles.float).to.equal("right") 47 | 48 | it 'should set "clear:both" if break passed in', -> 49 | styles = spanCalculate({break: true}) 50 | 51 | expect(styles.clear).to.equal("both") 52 | 53 | it 'should add marginLeft if pre is not 0', -> 54 | styles = spanCalculate({pre: 3, columns: 3}) 55 | noPrestyles = spanCalculate({pre: 0, columns: 3}) 56 | 57 | expect(noPrestyles.marginLeft).to.equal("0%") 58 | expect(styles.width).to.equal(noPrestyles.width) 59 | expect(styles.marginLeft).to.not.equal(noPrestyles.marginLeft) 60 | 61 | it 'should add marginRight if post is not 0', -> 62 | styles = spanCalculate({post: 1, columns: 1}) 63 | noPoststyles = spanCalculate({post: 0, columns: 1}) 64 | 65 | expect(styles.width).to.equal(noPoststyles.width) 66 | expect(styles.marginRight).to.not.equal(noPoststyles.marginRight) 67 | 68 | it 'should produce the same output for marginRight/marginLeft 69 | for squish as it does for pre/post', -> 70 | preStyles = spanCalculate({pre: 1, columns: 1}) 71 | postStyles = spanCalculate({post: 1, columns: 1}) 72 | squishStyles = spanCalculate({squish: 1, columns: 1}) 73 | 74 | expect(postStyles.marginRight).to.equal(squishStyles.marginRight) 75 | expect(preStyles.marginLeft).to.equal(squishStyles.marginLeft) 76 | 77 | it 'should add marginLeft if squish is not 0', -> 78 | styles = spanCalculate({squish: 3, columns: 3}) 79 | noSquishstyles = spanCalculate({squish: 0, columns: 3}) 80 | 81 | expect(noSquishstyles.marginLeft).to.equal("0%") 82 | expect(styles.width).to.equal(noSquishstyles.width) 83 | expect(styles.marginLeft).to.not.equal(noSquishstyles.marginLeft) 84 | 85 | it 'should eliminate extra right gutter if span is last', -> 86 | styles = spanCalculate({squish: 1, columns: 3, last: true}) 87 | 88 | expect(styles.marginLeft).to.equal(styles.marginRight) 89 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: [ 6 | "webpack-dev-server/client?http://0.0.0.0:8080", 7 | 'webpack/hot/only-dev-server', 8 | './examples/Router' 9 | ], 10 | devServer: { 11 | contentBase: './examples/', 12 | hot: true 13 | }, 14 | devtool: "eval", 15 | debug: true, 16 | output: { 17 | path: path.join(__dirname, 'examples'), 18 | filename: 'bundle.js', 19 | }, 20 | resolveLoader: { 21 | modulesDirectories: ['node_modules'] 22 | }, 23 | plugins: [ 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NoErrorsPlugin(), 26 | new webpack.IgnorePlugin(/un~$/) 27 | ], 28 | resolve: { 29 | extensions: ['', '.js', '.cjsx', '.coffee'] 30 | }, 31 | module: { 32 | loaders: [ 33 | { test: /\.css$/, loaders: ['style', 'css']}, 34 | { test: /\.cjsx$/, loaders: ['react-hot', 'coffee', 'cjsx']}, 35 | { test: /\.coffee$/, loader: 'coffee' } 36 | ] 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /webpack.config.production.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | 5 | module.exports = { 6 | entry: [ 7 | './examples/Router' 8 | ], 9 | output: { 10 | path: path.join(__dirname, 'examples'), 11 | filename: 'bundle.js', 12 | }, 13 | resolveLoader: { 14 | modulesDirectories: ['node_modules'] 15 | }, 16 | plugins: [ 17 | new webpack.DefinePlugin({ 18 | "process.env": { 19 | NODE_ENV: JSON.stringify("production") 20 | } 21 | }), 22 | new webpack.optimize.DedupePlugin(), 23 | new webpack.optimize.UglifyJsPlugin() 24 | ], 25 | resolve: { 26 | extensions: ['', '.js', '.cjsx', '.coffee'] 27 | }, 28 | module: { 29 | loaders: [ 30 | { test: /\.css$/, loaders: ['style', 'css']}, 31 | { test: /\.cjsx$/, loaders: ['coffee', 'cjsx']}, 32 | { test: /\.coffee$/, loader: 'coffee' } 33 | ] 34 | } 35 | }; 36 | --------------------------------------------------------------------------------