├── .babelrc
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── browsers.json
├── karma.conf.js
├── package.json
├── readme.md
├── src
├── align.js
├── center.js
├── column.js
├── defaults.js
├── flex-container.js
├── index.js
├── masonry.js
├── move.js
├── offset.js
├── perdido.js
├── row.js
├── utils.js
└── waffle.js
├── tests.webpack.js
├── tests
├── align-flex.js
├── align.js
├── center.js
├── column.js
├── creation.js
├── flex-container.js
├── helpers.js
├── index.html
├── index.js
├── masonly-column.js
├── masonry-wrap.js
├── move.js
├── offset.js
├── row.js
├── utils.js
└── waffle.js
├── tonic-example.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "passPerPreset": true,
3 | "presets": [
4 | "react",
5 | "es2015",
6 | "stage-0"
7 | ],
8 | "plugins": [
9 | "transform-runtime"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | test/
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "eslint-config-airbnb",
5 | "eslint-config-jss"
6 | ],
7 | "plugins": [
8 | "react"
9 | ],
10 | "env": {
11 | "browser": true
12 | },
13 | "rules": {
14 | "semi": [
15 | 2,
16 | "always"
17 | ],
18 | "brace-style": [
19 | 2,
20 | "1tbs",
21 | {
22 | "allowSingleLine": true
23 | }
24 | ]
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/tests/.*
3 |
4 | [include]
5 | src/*
6 |
7 | [libs]
8 |
9 | [options]
10 | esproposal.class_instance_fields=ignore
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | npm-debug.log
4 | tmp
5 | *~
6 | lib
7 | dist
8 | coverage
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | bench
3 | tmp
4 | test
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | git:
3 | depth: 10
4 |
5 | # remove the dist branch and dist tags from travis builds
6 | branches:
7 | except:
8 | - dist
9 | - /^v(\d+\.)?(\d+\.)?(\*|\d+)$/
10 |
11 | language: node_js
12 | node_js:
13 | - "5"
14 | - "node"
15 |
16 | # enable this once we have reliable builds
17 | cache:
18 | directories:
19 | - node_modules
20 |
21 | after_success:
22 | - bash <(curl -s https://codecov.io/bash)
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.5.0 / 2016-01-25
2 |
3 | - First release. Supports about half of Lost's API, untested.
4 |
5 | ## 0.5.1 / 2016-01-25
6 |
7 | - Bug fix to ensure dependencies are downloaded.
8 |
9 | ## 0.5.2 / 2016-01-25
10 |
11 | - Roll back Babel version to ensure build works, update coming later.
12 | -
13 | ## 0.5.3 / 2016-01-25
14 |
15 | - Improve the exported API object.
16 |
17 | ## 0.5.4 / 2016-01-25
18 |
19 | - Add a create method that gives users an easy way to override Perdido defaults.
20 |
21 | ## 0.6.0 / 2016-01-25
22 |
23 | - Add a move method that allows source ordering changes.
24 |
25 | ## 0.6.1 / 2016-01-25
26 |
27 | - Reorder the `create` method arguments so that it's easier to create a Perdido instance with only certain options overridden.
28 |
29 | ## 0.6.2 / 2016-01-25
30 |
31 | - Add test suite for 50% of the library.
32 | - Remove unnecessary dependency (reducing library size to 19.1kB uncompressed!)
33 |
34 | ## 0.7.0 / 2016-01-26
35 |
36 | - Complete test suite for library
37 | - add `Perdido.masonryColumn(..)` to allow working with Masonry grids
38 | - add `Perdido.masonryWrap(..)` to allow working with Masonry grids
39 | - add `Perdido.waffle(..)` to allow creating waffle grids.
40 |
41 | ## 0.7.1 / 2016-01-26
42 |
43 | - Improve the returned API so that you can import the create method separate from the default Perdido instance.
44 |
45 | ## 1.0.0 / 2016-01-27
46 |
47 | - Add documentation to library
48 | - Clean up code for linter
49 | - Stabalize API
50 |
51 | ## 1.0.1 / 2016-01-27
52 |
53 | - Improve documentation navigation.
54 |
55 | ## 1.0.2 / 2016-01-27
56 |
57 | - Add better Tonic example.
58 |
59 | ## 2.0.0 / 2016-01-28
60 |
61 | - API change, all optional arguments now come in option objects. So this
62 |
63 | ```js
64 | perdido.column('1/3', 2, '30px', true)
65 | ```
66 | Becomes this.
67 | ```js
68 | perdido.column('1/3', {cycle: 2, gutter: '30px', flex: true})
69 | ```
70 | This is across the entire public Perdido object API. If you import the various functions you are on your own, those functions have no default values and expect the arguments in the order declared.
71 |
72 | ## 2.0.1 / 2016-01-29
73 |
74 | - Add Coverage to Project.
75 | - Fix bugs discovered by uncovered code.
76 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Wellington Cordeiro
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/browsers.json:
--------------------------------------------------------------------------------
1 | {
2 | "BS_Safari": {
3 | "base": "BrowserStack",
4 | "os": "OS X",
5 | "os_version": "Yosemite",
6 | "browser": "safari",
7 | "browser_version": "8.0"
8 | },
9 | "BS_Safari": {
10 | "base": "BrowserStack",
11 | "os": "OS X",
12 | "os_version": "Mavericks",
13 | "browser": "safari",
14 | "browser_version": "7.0"
15 | },
16 | "BS_Chrome": {
17 | "base": "BrowserStack",
18 | "os": "OS X",
19 | "os_version": "Yosemite",
20 | "browser": "chrome",
21 | "browser_version": "49.0"
22 | },
23 | "BS_Firefox": {
24 | "base": "BrowserStack",
25 | "os": "OS X",
26 | "os_version": "Yosemite",
27 | "browser": "firefox",
28 | "browser_version": "45.0"
29 | },
30 | "BS_MobileSafari": {
31 | "base": "BrowserStack",
32 | "os": "ios",
33 | "os_version": "8.0",
34 | "browser": "iphone",
35 | "real_mobile": false
36 | },
37 | "BS_MobileSafari": {
38 | "base": "BrowserStack",
39 | "os": "ios",
40 | "os_version": "9.0",
41 | "browser": "iphone",
42 | "real_mobile": false
43 | },
44 | "BS_Chrome": {
45 | "base": "BrowserStack",
46 | "os": "Windows",
47 | "os_version": "8.1",
48 | "browser": "chrome",
49 | "browser_version": "49.0"
50 | },
51 | "BS_Firefox": {
52 | "base": "BrowserStack",
53 | "os": "Windows",
54 | "os_version": "8.1",
55 | "browser": "firefox",
56 | "browser_version": "45.0"
57 | },
58 | "BS_InternetExplorer9": {
59 | "base": "BrowserStack",
60 | "os": "Windows",
61 | "os_version": "7",
62 | "browser": "ie",
63 | "browser_version": "9.0"
64 | },
65 | "BS_InternetExplorer10": {
66 | "base": "BrowserStack",
67 | "os": "Windows",
68 | "os_version": "8",
69 | "browser": "ie",
70 | "browser_version": "10"
71 | },
72 | "BS_InternetExplorer11": {
73 | "base": "BrowserStack",
74 | "os": "Windows",
75 | "os_version": "8.1",
76 | "browser": "ie",
77 | "browser_version": "11.0"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | const assign = require('lodash.assign')
2 | const webpackConfig = require('./webpack.config')
3 | const browsers = require('./browsers')
4 |
5 | const isBench = process.env.BENCHMARK === 'true'
6 | const useCloud = process.env.USE_CLOUD === 'true'
7 | const browserStackUserName = process.env.BROWSER_STACK_USERNAME
8 | const browserStackAccessKey = process.env.BROWSER_STACK_ACCESS_KEY
9 | const isTravis = process.env.TRAVIS
10 | const travisBuildNumber = process.env.TRAVIS_BUILD_NUMBER
11 | const travisBuildId = process.env.TRAVIS_BUILD_ID
12 | const travisJobNumber = process.env.TRAVIS_JOB_NUMBER
13 |
14 | module.exports = (config) => {
15 | config.set({
16 | customLaunchers: browsers,
17 | browsers: ['Chrome', 'Firefox', 'Safari'],
18 | frameworks: ['mocha'],
19 | files: [
20 | 'node_modules/es5-shim/es5-shim.js',
21 | 'node_modules/es5-shim/es5-sham.js',
22 | 'tests.webpack.js'
23 | ],
24 | preprocessors: {
25 | 'tests.webpack.js': ['webpack', 'sourcemap']
26 | },
27 | webpack: assign(webpackConfig, {
28 | devtool: 'inline-source-map'
29 | }),
30 | webpackServer: {
31 | noInfo: true
32 | },
33 | reporters: ['mocha', 'coverage'],
34 | coverageReporter: {
35 | dir: 'coverage',
36 | file: 'coverage.json',
37 | type: 'json'
38 | }
39 | })
40 | if (isBench) {
41 | assign(config, {
42 | browsers: ['Chrome'],
43 | frameworks: ['benchmark'],
44 | files: ['benchmark/**/*.js'],
45 | preprocessors: {'benchmark/**/*.js': ['webpack']},
46 | reporters: ['benchmark']
47 | })
48 | }
49 |
50 | if (useCloud) {
51 | assign(config, {
52 | browsers: Object.keys(browsers),
53 | browserDisconnectTimeout: 10000,
54 | browserDisconnectTolerance: 3,
55 | browserNoActivityTimeout: 30000,
56 | captureTimeout: 200000
57 | })
58 |
59 | config.browserStack = {
60 | username: browserStackUserName,
61 | accessKey: browserStackAccessKey,
62 | pollingTimeout: 10000
63 | }
64 |
65 | if (isTravis) {
66 | assign(config.browserStack, {
67 | build: `TRAVIS #${travisBuildNumber} (${travisBuildId})`,
68 | name: travisJobNumber
69 | })
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "perdido",
3 | "version": "2.0.1",
4 | "description": "The Lost CSS grid reimagined to work with the JSS system",
5 | "author": {
6 | "name": "Wellington Cordeiro",
7 | "email": "wellington@wellingtoncordeiro.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git@github.com:wldcordeiro/perdido.git"
12 | },
13 | "keywords": [
14 | "jss",
15 | "plugin",
16 | "grid",
17 | "perdido",
18 | "style",
19 | "stylesheet"
20 | ],
21 | "engines": {
22 | "node": ">=4.0.0 <6.0.0"
23 | },
24 | "scripts": {
25 | "all": "npm run lint && npm run test && npm run build",
26 | "clean": "rimraf ./lib/*",
27 | "cover": "istanbul cover test/index.js",
28 | "build": "npm run clean && npm run build:lib && npm run build:max && npm run build:min",
29 | "build:lib": "babel src --out-dir lib",
30 | "build:max": "NODE_ENV=development webpack src/index.js dist/perdido.js",
31 | "build:min": "NODE_ENV=production webpack src/index.js dist/perdido.min.js",
32 | "build:test": "webpack tests/index.js tmp/tests.js",
33 | "lint": "eslint ./src ./tests",
34 | "prepublish": "npm run all && git push --tags",
35 | "test": "./node_modules/karma/bin/karma start --single-run",
36 | "test:watch": "karma start",
37 | "posttest": "[ -z \"$TRAVIS\" ] || codecov",
38 | "codecov": "codecov",
39 | "bench": "BENCHMARK=true npm run test"
40 | },
41 | "license": "MIT",
42 | "main": "./lib/index.js",
43 | "devDependencies": {
44 | "babel-cli": "^6.9.0",
45 | "babel-core": "^6.9.1",
46 | "babel-eslint": "^6.0.4",
47 | "babel-loader": "^6.2.4",
48 | "babel-plugin-transform-inline-environment-variables": "^6.8.0",
49 | "babel-plugin-transform-runtime": "^6.9.0",
50 | "babel-polyfill": "^6.9.1",
51 | "babel-preset-es2015": "^6.9.0",
52 | "babel-preset-react": "^6.5.0",
53 | "babel-preset-stage-0": "^6.5.0",
54 | "chai": "^3.5.0",
55 | "codecov": "^1.0.1",
56 | "es5-shim": "4.5.8",
57 | "eslint": "^2.11.1",
58 | "eslint-config-airbnb": "^8.0.0",
59 | "eslint-config-jss": "^1.1.0",
60 | "eslint-plugin-import": "^1.8.1",
61 | "eslint-plugin-jsx-a11y": "^1.3.0",
62 | "eslint-plugin-react": "^5.1.1",
63 | "expect.js": "^0.3.1",
64 | "istanbul": "^0.4.3",
65 | "jss": "^3.11.1",
66 | "jss-camel-case": "^1.1.0",
67 | "jss-default-unit": "^2.2.0",
68 | "jss-extend": "^1.2.1",
69 | "jss-nested": "^1.0.3",
70 | "jss-vendor-prefixer": "^2.0.0",
71 | "karma": "^0.13.22",
72 | "karma-browserstack-launcher": "^1.0.1",
73 | "karma-chrome-launcher": "^1.0.1",
74 | "karma-coverage": "^1.0.0",
75 | "karma-firefox-launcher": "^1.0.0",
76 | "karma-mocha": "^1.0.1",
77 | "karma-mocha-reporter": "^2.0.3",
78 | "karma-safari-launcher": "^1.0.0",
79 | "karma-sourcemap-loader": "^0.3.7",
80 | "karma-webpack": "^1.7.0",
81 | "mocha": "^2.5.3",
82 | "rimraf": "^2.5.2",
83 | "webpack": "^1.13.1"
84 | },
85 | "dependencies": {
86 | "jss": "^3.11.1",
87 | "jss-extend": "^1.2.1",
88 | "jss-nested": "^1.0.3",
89 | "jss-camel-case": "^1.1.0",
90 | "jss-default-unit": "^2.2.0",
91 | "jss-vendor-prefixer": "^2.0.0"
92 | },
93 | "tonicExampleFilename": "tonic-example.js"
94 | }
95 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Perdido JSS Grid System
2 | [](https://badge.fury.io/js/perdido)
3 |
4 | Perdido is a grid system for [JSS](https://github.com/jsstyles/jss), it is mostly a translation of the wonderful [Lost PostCSS Grid](https://github.com/peterramsing/lost) (thus the name as "perdido" means lost in Portuguese and Spanish.) Perdido comes with a set of functions that you can use in your JSS to create fluid grids easily.
5 |
6 | Perdido has requirements for the following JSS plugins, so make sure to install and initialize them.
7 |
8 | 1. jss-extend
9 | 2. jss-nested
10 | 3. jss-camel-case
11 | 4. jss-default-unit
12 | 5. jss-vendor-prefixer
13 |
14 | ## Table of Contents
15 |
16 | 1. [Example](#example)
17 | 2. [Guide](#guide)
18 | 1. [Basic Columns](#basic-columns)
19 | 2. [Centering Elements](#centering-elements)
20 | 3. [Controlling Cycle](#controlling-cycle)
21 | 4. [Nesting](#nesting)
22 | 5. [Offsetting Elements](#offsetting-elements)
23 | 6. [Alignment](#alignment)
24 | 7. [Edit Mode](#edit-mode)
25 | 8. [Vertical Grids](#vertical-grids)
26 | 9. [Waffle Grids](#waffle-grids)
27 | 10. [Flexbox Grids](#flexbox-grids)
28 | 11. [Masonry Support](#masonry-support)
29 | 3. [API](#api)
30 | 1. [`Perdido.utils`](#perdidoutils)
31 | 1. [`utils.edit`](#utilsedit)
32 | 2. [`utils.clearFix`](#utilsclearfix)
33 | 2. [`Perdido.align(..)`](#perdidoalign)
34 | 3. [`Perdido.center(..)`](#perdidocenter)
35 | 4. [`Perdido.column(..)`](#perdidocolumn)
36 | 5. [`Perdido.flexContainer(..)`](#perdidoflexcontainer)
37 | 6. [`Perdido.masonryColumn(..)`](#perdidomasonrycolumn)
38 | 7. [`Perdido.masonryWrap(..)`](#perdidomasonrywrap)
39 | 8. [`Perdido.move(..)`](#perdidomove)
40 | 9. [`Perdido.offset(..)`](#perdidooffset)
41 | 10. [`Perdido.row(..)`](#perdidorow)
42 | 11. [`Perdido.waffle(..)`](#perdidowaffle)
43 | 4. [Options](#options)
44 | 5. [Contributing](#contributing)
45 | 6. [Thanks](#thanks)
46 |
47 | ## Example
48 |
49 | Say we had a simple HTML block like a `section` with three inner `article`'s and we wanted to split it into a 1/3 grid. With Perdido we could do this to generate the `style` block containing your grid.
50 |
51 | ```html
52 |
53 | 1
54 | 2
55 | 3
56 |
57 | ```
58 |
59 | ```js
60 | // ES6/7/2015/whatever you call it
61 | import jss from 'jss';
62 | import extend from 'jss-extend';
63 | import nested from 'jss-nested';
64 | import camelCase from 'jss-camel-case';
65 | import defaultUnit from 'jss-default-unit';
66 | import vendorPrefixer from 'jss-vendor-prefixer';
67 | import perdido from 'perdido';
68 |
69 |
70 | jss.use(extend());
71 | jss.use(nested());
72 | jss.use(camelCase());
73 | jss.use(defaultUnit());
74 | jss.use(vendorPrefixer());
75 |
76 |
77 | var sectionStyle = {
78 | section: {
79 | '& article': {
80 | ...perdido.column('1/3'),
81 | }
82 | }
83 | }
84 |
85 | jss.createStyleSheet(sectionStyle, {named: false}).attach();
86 | ```
87 |
88 | The processed CSS that would be produced looks like this.
89 |
90 | ```css
91 | section article {
92 | width: calc(99.99% * 1/3 - (30px - 30px * 1/3));
93 | }
94 | section article:nth-child(n) {
95 | float: left;
96 | clear: none;
97 | margin-right: 30px;
98 | }
99 | section article:last-child {
100 | margin-right: 0;
101 | }
102 | section article:nth-child(3n) {
103 | float: right;
104 | margin-right: 0;
105 | }
106 | section article:nth-child(3n + 1) {
107 | clear: left;
108 | }
109 | ```
110 |
111 | **[:arrow_up: back to top](#table-of-contents)**
112 |
113 | ## Guide
114 |
115 | ### Basic Columns
116 |
117 | To create a basic horizontal grid, just insert some elements into any containing element like so and pass a fraction to the `Perdido.column` method. To unset (or remove) a column rule, possibly at a larger breakpoint, use `Perdido.column('none')`;
118 |
119 | ```html
120 |
121 |
1
122 |
2
123 |
3
124 |
4
125 |
126 | ```
127 |
128 | ```js
129 | {
130 | section: {
131 | ...perdido.utils.clearFix,
132 | '& div': {
133 | ...perdido.column('1/3'),
134 | }
135 | }
136 | }
137 | ```
138 |
139 | `Perdido.utils.clearFix` is just a [clearfix](http://nicolasgallagher.com/micro-clearfix-hack/) style object since Perdido Grid elements are floated. It's a good idea to give this to the element wrapping your grid elements every time you have nested floated elements.
140 |
141 | **[:arrow_up: back to top](#table-of-contents)**
142 |
143 | ### Centering Elements
144 |
145 | You can also make use of the `Perdido.center` property to assign a `max-width` and `margin: auto` to an element and center it on the page. clearfix will automatically be applied in this case.
146 |
147 | ```js
148 | {
149 | section: {
150 | ...perdido.center('980px'),
151 | '& div': {
152 | ...perdido.column('1/2'),
153 | }
154 | }
155 | }
156 | ```
157 |
158 | **[:arrow_up: back to top](#table-of-contents)**
159 |
160 | ### Controlling Cycle
161 |
162 | Every element gets a `float: left` and `margin-right: gutter` applied to it except the last element in the row and the last item in a container. Perdido will automatically detect the last item in a row (based on the denominator you passed) and apply a `margin-right: 0` to it by default.
163 |
164 | To override this behavior and tell Perdido to apply margin-right: 0 to a specific iteration, simply pass a cycle param to your `perdido.column` method. It's the second argument.
165 |
166 | ```js
167 | {
168 | div: {
169 | ...perdido.column('2/4', {cycle: 2}),
170 | }
171 | }
172 | ```
173 |
174 | This will tell Perdido to create `div:nth-child(2n) { margin-right: 0; }` *instead* of `div:nth-child(4n) { margin-right: 0; }` (like it would by default and break).
175 |
176 | Using this knowledge we can create really flexible layouts with varying widths like so (this will work for a single row nicely).
177 |
178 | ```html
179 |
180 |
1
181 |
2
182 |
3
183 |
184 | ```
185 |
186 | ```js
187 | {
188 | '.row': {
189 | ...perdido.utils.clearFix,
190 | },
191 | '.quarter': {
192 | ...perdido.column('1/4', {cycle: 0}),
193 | },
194 | '.half': {
195 | ...perdido.column('1/2', {cycle: 0}),
196 | },
197 | }
198 | ```
199 |
200 | The concept of cycle is extremely important to Perdido and what sets good Perdido developers apart from great Perdido developers. Really try to grok this!
201 |
202 | **[:arrow_up: back to top](#table-of-contents)**
203 |
204 | ### Nesting
205 |
206 | Nesting is simple. There is no context required.
207 |
208 | ```html
209 |
210 |
a
211 |
212 |
b
213 |
214 |
c
215 |
c
216 |
217 |
218 |
219 | ```
220 |
221 | ```js
222 | {
223 | div: {
224 | ...perdido.column('1/2'),
225 | }
226 | }
227 | ```
228 |
229 | **[:arrow_up: back to top](#table-of-contents)**
230 |
231 | ### Offsetting Elements
232 |
233 | You can offset columns easily. To offset in the other direction, pass a negative fraction.
234 |
235 | ```html
236 |
237 |
1
238 |
2
239 |
240 | ```
241 |
242 | ```js
243 | {
244 | div: {
245 | ...perdido.column('1/3'),
246 | '&:first-child' {
247 | ...perdido.offset('1/3'),
248 | }
249 | }
250 | }
251 | ```
252 |
253 | **[:arrow_up: back to top](#table-of-contents)**
254 |
255 | ### Alignment
256 |
257 | Easily align children elements with the `Perdido.align` method. It accepts options like top-left, right, center, [etc](#perdidoalign).
258 |
259 | ```html
260 |
261 |
Aligned
262 |
263 | ```
264 |
265 | ```js
266 | {
267 | section: {
268 | ...perdido.align('center'),
269 | width: '600px',
270 | height: '400px',
271 |
272 | '& div': {
273 | width: '100px',
274 | height: '100px',
275 | }
276 | }
277 | }
278 | ```
279 |
280 | **[:arrow_up: back to top](#table-of-contents)**
281 |
282 | ### Edit Mode
283 |
284 | Use `perdido.utils.edit` on `body` to visualize the entire structure of your site, or just specify the areas you're working on.
285 |
286 | ```html
287 |
288 |
1
289 |
2
290 |
3
291 |
292 |
293 |
294 |
4
295 |
5
296 |
6
297 |
298 | ```
299 |
300 | ```js
301 | {
302 | section: {
303 | '&:nth-of-type(1)': {
304 | ...perdido.utils.edit,
305 | },
306 | '&:nth-of-type(2)': {
307 | ...perdido.utils.edit,
308 | }
309 | }
310 | }
311 | ```
312 |
313 | **[:arrow_up: back to top](#table-of-contents)**
314 |
315 | ### Vertical Grids
316 |
317 | Once you've mastered the basic horizontal grid system (it shouldn't take long), you can start to make vertical grids that have the same vertical gutters as your horizontal grids. Just use the `perdido.row` method in place of `perdido.column`. These rows will stretch to fill their container's height, so if you'd like to see them take up the full height of the page, set `height: 100%` on your container.
318 |
319 | ```html
320 |
321 |
1
322 |
2
323 |
3
324 |
325 | ```
326 |
327 | ```js
328 | {
329 | section: {
330 | height: '100%',
331 | '& div': {
332 | ...perdido.row('1/3'),
333 | }
334 | }
335 | }
336 | ```
337 |
338 | **[:arrow_up: back to top](#table-of-contents)**
339 |
340 | ### Waffle Grids
341 |
342 | You can even make a horizontal/vertical grid (a **waffle grid**) which resembles a tic-tac-toe board.
343 |
344 | ```html
345 |
346 |
1
347 |
2
348 |
3
349 |
4
350 |
5
351 |
6
352 |
7
353 |
8
354 |
9
355 |
356 | ```
357 |
358 | ```js
359 | {
360 | section: {
361 | height: '100%',
362 | '& div': {
363 | ...perdido.waffle('1/3'),
364 | }
365 | }
366 | }
367 | ```
368 |
369 | **[:arrow_up: back to top](#table-of-contents)**
370 |
371 | ### Flexbox Grids
372 |
373 | You can easily change your grids to support Flexbox by altering the perdido property `flex` by setting it to `true`. Once you do this, all grids throughout your site will use flexed elements. To make sure they are displayed as flexed elements, you need to wrap them in `perdido.flexContainer` or `perdido.center` (which includes `perdido.flexContainer` by default).
374 |
375 | ```html
376 |
377 |
1
378 |
2
379 |
3
380 |
381 | ```
382 |
383 | ```js
384 | perdido.flex = true;
385 |
386 | {
387 | section: {
388 | ...perdido.center('980px'),
389 | },
390 | div: {
391 | ...perdido.column('1/3'),
392 | }
393 | }
394 | ```
395 |
396 | Flexbox offers slightly cleaner output and avoids the use of `clearfix` and other issues with float-based layouts. It also allows you to have elements of even height rather easily, and [much more](https://github.com/philipwalton/flexbugs/issues/32#issuecomment-90789645). The downside is, Flexbox doesn't work in IE9 or below, so keep that in mind if you have a client that needs that kind of support.
397 |
398 | Also note that waffle grids work well for the most part, but are somewhat finicky in fringe situations. All methods provide a way to disable or enable Flexbox per element with the `flex` parameter so if you'd like to disable it for a specific case you could do this:
399 |
400 | ```html
401 |
402 |
1
403 |
2
404 |
3
405 |
4
406 |
5
407 |
408 | ```
409 |
410 | ```js
411 | perdido.flex = true;
412 |
413 | {
414 | section: {
415 | ...perdido.center('980px', {flex: false}),
416 | },
417 | div: {
418 | ...perdido.waffle('1/3', {flex: false}),
419 | }
420 | }
421 | ```
422 |
423 | **[:arrow_up: back to top](#table-of-contents)**
424 |
425 | ### Masonry Support
426 |
427 | Perdido supports masonry plugins like [Isotope](http://isotope.metafizzy.co/). To accomplish this we need to change how the margins work. Instead of applying a `margin-right` to everything, we need to apply it to both sides. We've made a couple special methods to help with this: `perdido.masonryColumn` which creates a margin on the left and right of each element it's applied to, and `perdido.masonryWrap` which wraps your columns and applies a negative margin to the left and right to them to help line them up with containing elements.
428 |
429 | ```html
430 |
431 |
1
432 |
2
433 |
3
434 |
435 | ```
436 |
437 | ```js
438 | {
439 | section: {
440 | ...perdido.masonryWrap(false),
441 | '& div': {
442 | ...perdido.masonryColumn('1/3'),
443 | }
444 | }
445 | }
446 | ```
447 |
448 | **[:arrow_up: back to top](#table-of-contents)**
449 |
450 | ## API
451 |
452 | **NOTE: Bolded arguments are the required arguments.**
453 |
454 | ### `Perdido.utils`
455 |
456 | A general utility toolbelt for Perdido. Included are style objects that require no additional input other than being called.
457 |
458 |
459 | #### `utils.edit`
460 |
461 | Applies a background to the element for editing or debug purposes.
462 |
463 | ```js
464 | {
465 | section: {
466 | ...perdido.utils.edit,
467 | }
468 | }
469 | ```
470 |
471 | #### `utils.clearFix`
472 |
473 | Applies a clear fix to the element.
474 |
475 | ```js
476 | {
477 | section: {
478 | ...perdido.utils.clearFix,
479 | }
480 | }
481 | ```
482 |
483 | **[:arrow_up: back to top](#table-of-contents)**
484 |
485 | ### `Perdido.align(..)`
486 |
487 | Align nested elements. Apply this to a parent container.
488 |
489 | * **`reset|horizontal|vertical|top-left|top-center|top|top-right|middle-left|left|middle-center|center|middle-right|right|bottom-left|bottom-center|bottom|bottom-right` - The position the nested element takes relative to the containing element.**
490 | * `true|false` - Determines whether this element should use Flexbox or not.
491 |
492 | ```js
493 | {
494 | parent: {
495 | ...perdido.align('right'),
496 | width: '400px',
497 | height: '600px',
498 | },
499 | child: {
500 | width: '300px',
501 | height: '150px',
502 | }
503 | }
504 | ```
505 |
506 | **[:arrow_up: back to top](#table-of-contents)**
507 |
508 | ### `Perdido.center(..)`
509 |
510 | Horizontally center a container element and apply padding to it.
511 |
512 | * **`max-width` - A max-width to assign. Can be any unit.**
513 | * `padding` - Padding on the left and right of the element. Can be any unit.
514 | * `true|false` - Determines whether this element should use Flexbox or not.
515 |
516 | ```js
517 | {
518 | section: {
519 | ...perdido.center('980px'),
520 | },
521 | section: {
522 | ...perdido.center('1140px', {padding: '30px', flex: true}),
523 | },
524 | }
525 | ```
526 |
527 | **[:arrow_up: back to top](#table-of-contents)**
528 |
529 | ### `Perdido.column(..)`
530 |
531 | Creates a column that is a fraction of the size of its containing element's width with a gutter.
532 |
533 | * **`fraction` - This is a simple fraction of the containing element's width.**
534 | * `gutter` - The margin on the right side of the element used to create a gutter. Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
535 | * `cycle` - Perdido works by assigning a `margin-right` to all elements except the last in the row. It does this by default by using the denominator of the fraction you pick. To override the default use this param., e.g.: `{'.foo': { ...perdido.column('2/4' 2)}}``
536 | * `true|false` - Determines whether this element should use Flexbox or not.
537 | * `none` - Resets the column (back to browser defaults)
538 |
539 | ```js
540 | {
541 | div: {
542 | ...perdido.column('1/3'),
543 | },
544 | div: {
545 | ...perdido.column('2/6', {cycle: 3, gutter: '60px', flex: false}),
546 | }
547 | }
548 | ```
549 |
550 | **[:arrow_up: back to top](#table-of-contents)**
551 |
552 | ### `Perdido.flexContainer(..)`
553 |
554 | Creates a Flexbox container.
555 |
556 | * **`row|column` - The `flex-direction` the container should create. This is typically opposite to the element you're creating so a row would need `perdido.flexContainer('column')`.**
557 |
558 | ```js
559 | {
560 | section: {
561 | ...perdido.flexContainer('row'),
562 | },
563 | div: {
564 | ...perdido.column('1/3'),
565 | }
566 | }
567 | ```
568 |
569 | **[:arrow_up: back to top](#table-of-contents)**
570 |
571 | ### `Perdido.masonryWrap(..)`
572 |
573 | Creates a wrapping element for working with JS Masonry libraries like Isotope. Assigns a negative margin on each side of this wrapping element.
574 |
575 | * `true|false` - Determines whether this element should use Flexbox or not.
576 | * `gutter` - How large the gutter involved is, typically this won't be adjusted and will inherit settings.gutter, but it's made available if you want your masonry grid to have a special gutter, it should match your masonry-column's gutter.
577 |
578 | ```js
579 | {
580 | section: {
581 | ...perdido.masonryWrap({flex: false}),
582 | },
583 | div: {
584 | ...perdido.masonryColumn('1/3'),
585 | }
586 | }
587 | ```
588 |
589 | **[:arrow_up: back to top](#table-of-contents)**
590 |
591 | ### `Perdido.masonryColumn(..)`
592 |
593 | Creates a column for working with JS masonry libraries like Isotope. Assigns a margin to each side of the element.
594 |
595 | * **`fraction` - This is a simple fraction of the containing element's width**
596 | * `gutter` - How large the gutter involved is, typically this won't be adjusted and will inherit settings.gutter, but it's made available if you want your masonry grid to have a special gutter, it should match your masonry-row's gutter.
597 | * `true|false` - Determines whether this element should use Flexbox or not.
598 |
599 | ```js
600 | {
601 | section: {
602 | ...perdido.masonryWrap(true, '60px'),
603 | },
604 | div: {
605 | ...perdido.masonryColumn('1/3', {gutter: '60px', flex: true}),
606 | }
607 | }
608 | ```
609 |
610 | **[:arrow_up: back to top](#table-of-contents)**
611 |
612 | ### `Perdido.move(..)`
613 |
614 | Source ordering. Shift elements left, right, up, or down, by their left or top position by passing a positive or negative fraction.
615 |
616 | * **`fraction` - Fraction of the container to be shifted.**
617 | * `row|column` - Direction the grid is going. Should be the opposite of the column or row it's being used on.
618 | * `gutter` - Adjust the size of the gutter for this movement. Should match the element's gutter.
619 |
620 | ```js
621 | {
622 | div: {
623 | ...perdido.column('1/2'),
624 |
625 | '&:first-child': {
626 | ..perdido.move('1/2'),
627 | },
628 | '&:last-child': {
629 | ..perdido.move('-1/2'),
630 | }
631 | }
632 | }
633 | ```
634 |
635 | note: If a gutter is set, `perdido.move` will not retain it and will need to be set manually
636 |
637 | ```js
638 | {
639 | div: {
640 | ...perdido.column('1/2', {gutter: '0'}),
641 |
642 | '&:first-child': {
643 | ..perdido.move('1/2', {gutter: '0'}),
644 | },
645 | '&:last-child': {
646 | ..perdido.move('-1/2', {gutter: '0'}),
647 | }
648 | }
649 | }
650 | ```
651 |
652 | **[:arrow_up: back to top](#table-of-contents)**
653 |
654 | ### `Perdido.offset(..)`
655 |
656 | Margin to the left, right, bottom, or top, of an element depending on if the fraction passed is positive or negative. It works for both horizontal and vertical grids but not both.
657 |
658 | * **`fraction` - Fraction of the container to be offset.**
659 | * `row|column` - Direction the grid is going. Should be the opposite of the column or row it's being used on. Defaults to row.
660 | * `gutter` - How large the gutter involved is, typically this won't be adjusted, but if you have set the elements for that container to have different gutters than default, you will need to match that gutter here as well.
661 |
662 | ```js
663 | {
664 | '.two-elements': {
665 | ...perdido.column('1/3'),
666 | '&:first-child': {
667 | ...perdido.offset('1/3')
668 | }
669 | }
670 | }
671 | ```
672 |
673 | **[:arrow_up: back to top](#table-of-contents)**
674 |
675 | ### `Perdido.row(..)`
676 |
677 | Creates a row that is a fraction of the size of its containing element's height with a gutter.
678 |
679 | * **`fraction` - This is a simple fraction of the containing element's height.**
680 | * `gutter` - The margin on the bottom of the element used to create a gutter. Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
681 | * `true|false` - Determines whether this element should use Flexbox or not.
682 |
683 | ```js
684 | {
685 | section: {
686 | height: '100%',
687 | },
688 | div: {
689 | ...perdido.row('1/3'),
690 | }
691 | }
692 | ```
693 |
694 | **[:arrow_up: back to top](#table-of-contents)**
695 |
696 | ### `Perdido.waffle(..)`
697 |
698 | * **`fraction` - This is a simple fraction of the containing element's width and height.**
699 | * `cycle` - Perdido works by assigning a `margin-right/margin-bottom` to all elements except the last in the row. It does this by default by using the denominator of the fraction you pick. To override the default use this param., e.g.: `{'.foo': { ...perdido.waffle('2/4' 2)}}``
700 | * `gutter` - Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
701 | * `true|false` - Determines whether this element should use Flexbox or not.
702 |
703 | ```js
704 | {
705 | section: {
706 | height: '100%',
707 | },
708 | div: {
709 | ...perdido.waffle('1/3'),
710 | }
711 | }
712 | ```
713 |
714 | **[:arrow_up: back to top](#table-of-contents)**
715 |
716 | ## Options
717 |
718 | Perdido comes with some default settings that can be changed to your liking.
719 |
720 | ```js
721 | // ES6/2015
722 | import {create} from 'perdido';
723 |
724 | const perdido = create({gutter: '20px', flex: true, cycle: 3, offsetDir: 'column'});
725 | ```
726 |
727 | * `Perdido.gutter` accepts any unit value (default: '30px')
728 |
729 | * `Perdido.flex` accepts a boolean value (default: false)
730 |
731 | * `Perdido.cycle` accepts a integer value (default: -1 for auto cycle)
732 |
733 | * `Perdido.offsetDir` accepts a string of either 'row' or 'column' (default: row)
734 |
735 | **[:arrow_up: back to top](#table-of-contents)**
736 |
737 | ## Contributing
738 |
739 | Contributions are very welcome, and always appreciated! Every
740 | bit helps, and credit will always be given.
741 |
742 | **[:arrow_up: back to top](#table-of-contents)**
743 |
744 | ## Thanks
745 |
746 | * The [Lost CSS Grid team](https://github.com/peterramsing/lost) for making an awesome grid for me to base this on.
747 |
748 | **[:arrow_up: back to top](#table-of-contents)**
749 |
--------------------------------------------------------------------------------
/src/align.js:
--------------------------------------------------------------------------------
1 | /**
2 | * alignProps: Simple helper function that returns the appropriate JSON
3 | * object for the style block.
4 | *
5 | * @param {string} position value for position rule
6 | * @param {string} top value for top rule
7 | * @param {string} right value for right rule
8 | * @param {string} bottom value for bottom rule
9 | * @param {string} left value for left rule
10 | * @param {string} transform value for transform rule
11 | * @return {object} An object containing the valid JSS rules and
12 | * values.
13 | */
14 | function alignProps(position, top, right, bottom, left, transform) {
15 | return {
16 | position,
17 | top,
18 | right,
19 | bottom,
20 | left,
21 | transform,
22 | };
23 | }
24 |
25 | /**
26 | * Perdido.align: Align nested elements. Apply this to a parent container.
27 | *
28 | * @param {string} [reset|horizontal|vertical|top-left|top-center|top|
29 | * top-right|middle-left|left|middle-center|center|middle-right|right|
30 | * bottom-left|bottom-center|bottom|bottom-right] - The position the nested
31 | * element takes relative to the containing element.
32 | * @param {boolean} - Determines whether this element should use Flexbox or not.
33 | * @return {object} an object containing the valid JSS rules and values to align
34 | * nested elements.
35 | */
36 |
37 | export default function align(alignment, flex) {
38 | const style = {};
39 |
40 | if (flex === false) {
41 | if (alignment === 'reset') {
42 | style.position = 'static';
43 |
44 | style['& > *'] = alignProps(
45 | 'static',
46 | 'auto',
47 | 'auto',
48 | 'auto',
49 | 'auto',
50 | 'translate(0, 0)'
51 | );
52 | } else {
53 | style.position = 'relative';
54 |
55 | if (alignment === 'horizontal') {
56 | style['& > *'] = alignProps(
57 | 'absolute',
58 | 'auto',
59 | 'auto',
60 | 'auto',
61 | '50%',
62 | 'translate(-50%, 0)'
63 | );
64 | } else if (alignment === 'vertical') {
65 | style['& > *'] = alignProps(
66 | 'absolute',
67 | '50%',
68 | 'auto',
69 | 'auto',
70 | 'auto',
71 | 'translate(0, -50%)'
72 | );
73 | } else if (alignment === 'top-left') {
74 | style['& > *'] = alignProps(
75 | 'absolute',
76 | '0',
77 | 'auto',
78 | 'auto',
79 | '0',
80 | 'translate(0, 0)'
81 | );
82 | } else if (alignment === 'top-center' || alignment === 'top') {
83 | style['& > *'] = alignProps(
84 | 'absolute',
85 | '0',
86 | 'auto',
87 | 'auto',
88 | '50%',
89 | 'translate(-50%, 0)'
90 | );
91 | } else if (alignment === 'top-right') {
92 | style['& > *'] = alignProps(
93 | 'absolute',
94 | '0',
95 | '0',
96 | 'auto',
97 | 'auto',
98 | 'translate(0, 0)'
99 | );
100 | } else if (alignment === 'middle-left' || alignment === 'left') {
101 | style['& > *'] = alignProps(
102 | 'absolute',
103 | '50%',
104 | 'auto',
105 | 'auto',
106 | '0',
107 | 'translate(0, -50%)'
108 | );
109 | } else if (alignment === 'middle-center' || alignment === 'center') {
110 | style['& > *'] = alignProps(
111 | 'absolute',
112 | '50%',
113 | 'auto',
114 | 'auto',
115 | '50%',
116 | 'translate(-50%, -50%)'
117 | );
118 | } else if (alignment === 'middle-right' || alignment === 'right') {
119 | style['& > *'] = alignProps(
120 | 'absolute',
121 | '50%',
122 | '0',
123 | 'auto',
124 | 'auto',
125 | 'translate(0, -50%)'
126 | );
127 | } else if (alignment === 'bottom-left') {
128 | style['& > *'] = alignProps(
129 | 'absolute',
130 | 'auto',
131 | 'auto',
132 | '0',
133 | '0',
134 | 'translate(0, 0)'
135 | );
136 | } else if (alignment === 'bottom-center' || alignment === 'bottom') {
137 | style['& > *'] = alignProps(
138 | 'absolute',
139 | 'auto',
140 | 'auto',
141 | '0',
142 | '50%',
143 | 'translate(-50%, 0)'
144 | );
145 | } else if (alignment === 'bottom-right') {
146 | style['& > *'] = alignProps(
147 | 'absolute',
148 | 'auto',
149 | '0',
150 | '0',
151 | 'auto',
152 | 'translate(0, 0)'
153 | );
154 | }
155 | }
156 | } else {
157 | if (alignment === 'reset') {
158 | style.display = 'initial';
159 |
160 | style['& > *'] = {
161 | justifyContent: 'inherit',
162 | alignItems: 'inherit',
163 | };
164 | } else {
165 | style.display = 'flex';
166 |
167 | if (alignment === 'horizontal') {
168 | style['& > *'] = {
169 | justifyContent: 'center',
170 | alignItems: 'inherit',
171 | };
172 | } else if (alignment === 'vertical') {
173 | style['& > *'] = {
174 | justifyContent: 'inherit',
175 | alignItems: 'center',
176 | };
177 | } else if (alignment === 'top-left') {
178 | style['& > *'] = {
179 | justifyContent: 'flex-start',
180 | alignItems: 'flex-start',
181 | };
182 | } else if (alignment === 'top-center' || alignment === 'top') {
183 | style['& > *'] = {
184 | justifyContent: 'center',
185 | alignItems: 'flex-start',
186 | };
187 | } else if (alignment === 'top-right') {
188 | style['& > *'] = {
189 | justifyContent: 'flex-end',
190 | alignItems: 'flex-start',
191 | };
192 | } else if (alignment === 'middle-left' || alignment === 'left') {
193 | style['& > *'] = {
194 | justifyContent: 'flex-start',
195 | alignItems: 'center',
196 | };
197 | } else if (alignment === 'middle-center' || alignment === 'center') {
198 | style['& > *'] = {
199 | justifyContent: 'center',
200 | alignItems: 'center',
201 | };
202 | } else if (alignment === 'middle-right' || alignment === 'right') {
203 | style['& > *'] = {
204 | justifyContent: 'flex-end',
205 | alignItems: 'center',
206 | };
207 | } else if (alignment === 'bottom-left') {
208 | style['& > *'] = {
209 | justifyContent: 'flex-start',
210 | alignItems: 'flex-end',
211 | };
212 | } else if (alignment === 'bottom-center' || alignment === 'bottom') {
213 | style['& > *'] = {
214 | justifyContent: 'center',
215 | alignItems: 'flex-end',
216 | };
217 | } else if (alignment === 'bottom-right') {
218 | style['& > *'] = {
219 | justifyContent: 'flex-end',
220 | alignItems: 'flex-end',
221 | };
222 | }
223 | }
224 | }
225 |
226 | return style;
227 | }
228 |
--------------------------------------------------------------------------------
/src/center.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.center: Horizontally center a containing element and apply padding
3 | * to it.
4 | *
5 | * @param {length} maxWidth a max width to assign of any unit type.
6 | * @param {length} padding left and right padding on the element, can be
7 | * any unit.
8 | * @param {boolean} flex determines whether to use flex or not.
9 | * @return {object} an object containing the valid JSS rules and values
10 | * to center containing elements.
11 | */
12 |
13 |
14 | export default function center(maxWidth, padding, flex) {
15 | const style = {
16 | maxWidth,
17 | marginLeft: 'auto',
18 | marginRight: 'auto',
19 | };
20 |
21 | if (padding) {
22 | style.paddingLeft = padding;
23 | style.paddingRight = padding;
24 | }
25 |
26 | if (flex === false) {
27 | style['&:before'] = {
28 | content: "''",
29 | display: 'table',
30 | };
31 |
32 | style['&:after'] = {
33 | content: "''",
34 | display: 'table',
35 | clear: 'both',
36 | };
37 | } else {
38 | style.display = 'flex';
39 | style.flexFlow = 'row wrap';
40 | }
41 |
42 | return style;
43 | }
44 |
--------------------------------------------------------------------------------
/src/column.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.column: Creates a column that is a fraction of the size of its
3 | * containing element's width with a gutter.
4 | *
5 | * @param {string} [fraction] - This is a simple fraction of the containing
6 | * element's width.
7 | * @param {integer} [cycle] - Perdido works by assigning a margin-right to all
8 | * elements except the last in the row. If settings.cycle is set to auto
9 | * it will do this by default by using the denominator of the fraction you
10 | * pick. To override the default use this param.,
11 | * e.g.: {'.foo': { extend: Perdido.column('2/4', 2)}}
12 | * @param {length} [gutter] - how many units wide the gutter should be.
13 | * @param {boolean} - Determines whether this element should use Flexbox
14 | * or not.
15 | * @return {object} an object containing the valid JSS rules and values to
16 | * create a column.
17 | */
18 | export default function column(columnVal, cycle, gutter, flex) {
19 | const style = {};
20 | let cycleVal = cycle;
21 |
22 |
23 | if (columnVal !== 'none') {
24 | if (cycle === -1) {
25 | cycleVal = parseInt(columnVal.split('/')[1], 10);
26 | } else {
27 | cycleVal = cycle;
28 | }
29 |
30 | if (gutter !== '0') {
31 | style.width =
32 | `calc(99.99% * ${columnVal} - (${gutter} - ${gutter} * ${columnVal}))`;
33 | } else {
34 | style.width = `calc(99.999999% * ${columnVal})`;
35 | }
36 |
37 | if (flex === true) {
38 | style.flex = '0 0 auto';
39 |
40 | style['&:nth-child(n)'] = {
41 | marginRight: gutter,
42 | };
43 |
44 | style['&:last-child'] = {
45 | marginRight: '0',
46 | };
47 |
48 | style[`&:nth-child(${cycleVal}n)`] = {
49 | float: 'right',
50 | };
51 |
52 | if (cycle !== 0) {
53 | style[`&:nth-child(${cycleVal}n)`].marginRight = '0';
54 | }
55 | } else {
56 | style['&:nth-child(n)'] = {
57 | float: 'left',
58 | marginRight: gutter,
59 | clear: 'none',
60 | };
61 |
62 | style['&:last-child'] = {
63 | marginRight: '0',
64 | };
65 |
66 | style[`&:nth-child(${cycleVal}n)`] = {
67 | float: 'right',
68 | };
69 |
70 | if (cycle !== 0) {
71 | style[`&:nth-child(${cycleVal}n)`].marginRight = '0';
72 |
73 | style[`&:nth-child(${cycleVal}n + 1)`] = {
74 | clear: 'left',
75 | };
76 | }
77 | }
78 | } else {
79 | style.width = 'auto';
80 |
81 | style['&:last-child'] = {
82 | float: 'none',
83 | clear: 'none',
84 | marginRight: '0',
85 | width: 'auto',
86 | };
87 |
88 | style['&:nth-child(n)'] = {
89 | float: 'none',
90 | clear: 'none',
91 | marginRight: '0',
92 | width: 'auto',
93 | };
94 |
95 | style['&:nth-child(1n + 1)'] = {
96 | float: 'none',
97 | clear: 'none',
98 | marginRight: '0',
99 | width: 'auto',
100 | };
101 |
102 | style['&:nth-child(1n)'] = {
103 | float: 'none',
104 | clear: 'none',
105 | marginRight: '0',
106 | width: 'auto',
107 | };
108 | }
109 |
110 | return style;
111 | }
112 |
--------------------------------------------------------------------------------
/src/defaults.js:
--------------------------------------------------------------------------------
1 | /**
2 | * GUTTER: The default length of the gutters in Perdido grids.
3 | * @type {string}
4 | */
5 | export const GUTTER = '30px';
6 | /**
7 | * FLEX: Whether to utilize flexbox or not.
8 | * @type {boolean}
9 | */
10 | export const FLEX = false;
11 | /**
12 | * CYCLE: Which column to cycle or for margin-right, defaults to auto, allowing
13 | * Perdido to decide..
14 | * @type {string}
15 | */
16 | export const CYCLE = -1;
17 | /**
18 | * OFFSET_DIR: The default direct of the offsets in Perdido grids.
19 | * @type {string}
20 | */
21 | export const OFFSET_DIR = 'row';
22 |
--------------------------------------------------------------------------------
/src/flex-container.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.flexContainer: Creates a Flexbox container.
3 | *
4 | * @param {string} [row|column] - The flex-direction the container should
5 | * create. This is typically opposite to the element you're creating so a
6 | * row would need `Perdido.flexContainer('column')`.
7 | * @return {object} an object containing the valid JSS rules and values to
8 | * create a flexbox container.
9 | */
10 | export default function flexContainer(direction) {
11 | const style = {
12 | display: 'flex',
13 | };
14 |
15 | if (direction === 'column') {
16 | style.flexFlow = 'column nowrap';
17 | } else {
18 | style.flexFlow = 'row wrap';
19 | }
20 |
21 | return style;
22 | }
23 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Fluid Grid Systems in JSS, Perdido, a translation of Lost.
3 | *
4 | * @copyright Wellington Cordeiro 2015
5 | * @website https://github.com/wldcordeiro/perdido
6 | * @license MIT
7 | */
8 |
9 | import Perdido from './perdido';
10 |
11 | const perdido = new Perdido();
12 |
13 | export default perdido;
14 |
--------------------------------------------------------------------------------
/src/masonry.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.masonryColumn: Creates a column for working with JS masonry
3 | * libraries like Isotope. Assigns a margin to
4 | * each side of the element.
5 | *
6 | * @param {string} columnVal fraction of the containing element's size.
7 | * @param {string} gutter how many units wide the gutter should be.
8 | * @param {boolean} flex boolean that determines whether to use flexbox.
9 | * @return {object} an object containing the valid JSS rules and values to
10 | * create a masonry grid column.
11 | */
12 | export function masonryColumn(columnVal, gutter, flex) {
13 | const style = {};
14 | let unit = gutter.match(/\D/g);
15 |
16 | if (unit !== null) {
17 | unit = unit.join('');
18 | }
19 |
20 | if (flex === true) {
21 | style.flex = '0 0 auto';
22 | } else {
23 | style.float = 'left';
24 | }
25 |
26 | if (gutter !== '0') {
27 | style.width = `calc(99.99% * ${columnVal} - ${gutter})`;
28 | style.marginLeft = `${parseInt(gutter, 10) / 2}${unit}`;
29 | style.marginRight = `${parseInt(gutter, 10) / 2}${unit}`;
30 | } else {
31 | style.width = `calc(99.99% * ${columnVal})`;
32 | }
33 |
34 | return style;
35 | }
36 |
37 | /**
38 | * Perdido.masonryWrap: Creates a wrapping element for working with JS Masonry
39 | * libraries like Isotope. Assigns a negative margin on
40 | * each side of this wrapping element.
41 | *
42 | * @param {boolean} flex boolean that determines whether to use flexbox.
43 | * @param {string} gutter how many units wide the gutter should be.
44 | * @return {object} an object containing the valid JSS rules and values to
45 | * create a masonry grid wrapping element.
46 | */
47 | export function masonryWrap(flex, gutter) {
48 | const style = {};
49 | if (flex === false) {
50 | style['&:before'] = {
51 | content: "''",
52 | display: 'table',
53 | };
54 |
55 | style['&:after'] = {
56 | content: "''",
57 | display: 'table',
58 | clear: 'both',
59 | };
60 | } else {
61 | style.display = 'flex';
62 | style.flexFlow = 'row wrap';
63 | }
64 |
65 | const unit = gutter.match(/\D/g).join('');
66 |
67 | style.marginLeft = `${parseInt(gutter, 10) / -2}${unit}`;
68 | style.marginRight = `${parseInt(gutter, 10) / -2}${unit}`;
69 |
70 | return style;
71 | }
72 |
--------------------------------------------------------------------------------
/src/move.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.move: Source ordering. Shift elements left, right, up, or down, by
3 | * their left or top position by passing a positive or negative
4 | * fraction.
5 | * @param {string} moveVal fraction of the container to be shifted.
6 | * @param {string} direction direction the grid should be going. Should
7 | * be opposite of column or row it's being used on.
8 | * @param {string} gutter Adjust the size of the gutter for this movement.
9 | * Should match the element's gutter.
10 | * @return {object} an object containing the valid JSS rules and values to shift
11 | * an element around the grid.
12 | */
13 | export default function move(moveVal, direction, gutter) {
14 | const style = {
15 | position: 'relative',
16 | };
17 |
18 | if (direction === 'column') {
19 | if (gutter !== '0') {
20 | style.top = [
21 | `calc(99.99% * ${moveVal} - (${gutter} - ${gutter}`,
22 | ` * ${moveVal}) + ${gutter})`].join('');
23 | } else {
24 | style.top = `calc(99.999999% * ${moveVal})`;
25 | }
26 | } else {
27 | if (gutter !== '0') {
28 | style.left = [
29 | `calc(99.99% * ${moveVal} - (${gutter} - ${gutter}`,
30 | ` * ${moveVal}) + ${gutter})`].join('');
31 | } else {
32 | style.left = `calc(99.999999% * ${moveVal})`;
33 | }
34 | }
35 |
36 | return style;
37 | }
38 |
--------------------------------------------------------------------------------
/src/offset.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.offset: Margin to the left, right, bottom, or top, of an element
3 | * depending on if the fraction passed is positive or negative. It works for
4 | * both horizontal and vertical grids but not both.
5 | *
6 | * @param {string} offsetVal Fraction of the container to be offset.
7 | * @param {string} direction Direction the grid is going. Should be the
8 | * opposite of the column or row it's being used on.
9 | * Defaults to row.
10 | * @param {string} gutter How large the gutter involved is.
11 | * @return {object} An object containing the valid JSS rules and
12 | * values to offset elements.
13 | */
14 | export default function offset(offsetVal, direction, gutter) {
15 | const style = {};
16 | const numerator = parseInt(offsetVal.split('/')[0], 10);
17 |
18 | if (direction === 'column') {
19 | if (numerator > 0) {
20 | if (gutter !== '0') {
21 | style.marginBottom = [
22 | `calc(99.99% * ${offsetVal} - (${gutter} - ${gutter} * ${offsetVal})`,
23 | ` + (${gutter} * 2)) !important`].join('');
24 | } else {
25 | style.marginBottom = `calc(99.999999% * ${offsetVal}) !important`;
26 | }
27 | } else if (numerator < 0) {
28 | if (gutter !== '0') {
29 | style.marginTop = [
30 | `calc(99.99% * (${offsetVal} * -1) - `,
31 | `(${gutter} - ${gutter} * (${offsetVal} * -1))`,
32 | ` + ${gutter}) !important`].join('');
33 | } else {
34 | style.marginTop = `calc(99.999999% * ${offsetVal}) !important`;
35 | }
36 | } else {
37 | style.marginTop = '0 !important';
38 | style.marginBottom = `${gutter} !important`;
39 | }
40 | } else {
41 | if (numerator > 0) {
42 | if (gutter !== '0') {
43 | style.marginRight = [
44 | `calc(99.99% * ${offsetVal} - (${gutter} - ${gutter}`,
45 | ` * ${offsetVal}) + (${gutter} * 2)) !important`].join('');
46 | } else {
47 | style.marginRight = `calc(99.999999% * ${offsetVal}) !important`;
48 | }
49 | } else if (numerator < 0) {
50 | if (gutter !== '0') {
51 | style.marginLeft = [
52 | `calc(99.99% * (${offsetVal} * -1) - `,
53 | `(${gutter} - ${gutter} * (${offsetVal} * -1))`,
54 | ` + ${gutter}) !important`].join('');
55 | } else {
56 | style.marginLeft = `calc(99.999999% * ${offsetVal}) !important`;
57 | }
58 | } else {
59 | style.marginLeft = '0 !important';
60 | style.marginRight = `${gutter} !important`;
61 | }
62 | }
63 |
64 | return style;
65 | }
66 |
--------------------------------------------------------------------------------
/src/perdido.js:
--------------------------------------------------------------------------------
1 | import align from './align';
2 | import center from './center';
3 | import column from './column';
4 | import flexContainer from './flex-container';
5 | import {masonryColumn, masonryWrap} from './masonry';
6 | import move from './move';
7 | import offset from './offset';
8 | import row from './row';
9 | import * as utils from './utils';
10 | import waffle from './waffle';
11 | import {GUTTER, FLEX, CYCLE, OFFSET_DIR} from './defaults';
12 |
13 |
14 | /**
15 | * Main Perdido class.
16 | *
17 | * @api public
18 | */
19 | export default class Perdido {
20 | constructor(
21 | gutter = GUTTER,
22 | flex = FLEX,
23 | cycle = CYCLE,
24 | offsetDir = OFFSET_DIR) {
25 | // Set the default values.
26 | this.gutter = gutter;
27 | this.flex = flex;
28 | this.cycle = cycle;
29 | this.offsetDir = offsetDir;
30 |
31 | // Simple properties/methods.
32 | this.flexContainer = flexContainer;
33 | this.utils = utils;
34 | }
35 |
36 | /**
37 | * Creates a new instance of Perdido.
38 | *
39 | * @see Perdido
40 | * @api public
41 | */
42 | create({
43 | gutter = GUTTER,
44 | flex = FLEX,
45 | cycle = CYCLE,
46 | offsetDir = OFFSET_DIR} = {}) {
47 | return new Perdido(gutter, flex, cycle, offsetDir);
48 | }
49 |
50 | /**
51 | * Aligns nested elements.
52 | *
53 | * @see align
54 | * @api public
55 | */
56 | align(alignment, {flex = this.flex} = {}) {
57 | return align(alignment, flex);
58 | }
59 |
60 | /**
61 | * Centers a containing element.
62 | *
63 | * @see center
64 | * @api public
65 | */
66 | center(maxWidth, {padding, flex = this.flex} = {}) {
67 | return center(maxWidth, padding, flex);
68 | }
69 |
70 | /**
71 | * Creates a column that is a fraction of its containing element's size.
72 | *
73 | * @see column
74 | * @api public
75 | */
76 | column(columnVal, {
77 | cycle = this.cycle,
78 | gutter = this.gutter,
79 | flex = this.flex} = {}) {
80 | return column(columnVal, cycle, gutter, flex);
81 | }
82 |
83 | /**
84 | * Create a column for working with JS Masonry libraries like Isotope.
85 | *
86 | * @see masonry.masonryColumn
87 | * @api public
88 | */
89 | masonryColumn(columnVal, {gutter = this.gutter, flex = this.flex} = {}) {
90 | return masonryColumn(columnVal, gutter, flex);
91 | }
92 |
93 | /**
94 | * Create a wrapping element for working with JS Masonry libraries
95 | * like Isotope.
96 | *
97 | * @see masonry.masonryWrap
98 | * @api public
99 | */
100 | masonryWrap({flex = this.flex, gutter = this.gutter} = {}) {
101 | return masonryWrap(flex, gutter);
102 | }
103 |
104 | /**
105 | * Source ordering. Shift elements left, right, up, or down.
106 | *
107 | * @see move
108 | * @api public
109 | */
110 | move(moveVal, {direction = this.offsetDir, gutter = this.gutter} = {}) {
111 | return move(moveVal, direction, gutter);
112 | }
113 |
114 | /**
115 | * Margin to the left, right, bottom, or top, of an element.
116 | *
117 | * @see offset
118 | * @api public
119 | */
120 | offset(offsetVal, {direction = this.offsetDir, gutter = this.gutter} = {}) {
121 | return offset(offsetVal, direction, gutter);
122 | }
123 |
124 | /**
125 | * Creates a row that is a fraction of its containing element's size.
126 | *
127 | * @see row
128 | * @api public
129 | */
130 | row(rowVal, {gutter = this.gutter, flex = this.flex} = {}) {
131 | return row(rowVal, gutter, flex);
132 | }
133 |
134 | /**
135 | * Creates a block that is a fraction of the size of its containing element.
136 | *
137 | * @see waffle
138 | * @api public
139 | */
140 | waffle(waffleVal, {
141 | cycle = this.cycle,
142 | gutter = this.gutter,
143 | flex = this.flex} = {}) {
144 | return waffle(waffleVal, cycle, gutter, flex);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/row.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.row: Creates a row that is a fraction of the size of its containing
3 | * element's height with a gutter.
4 | *
5 | * @param {string} rowVal fraction of the containing element's height.
6 | * @param {string} gutter The bottom margin size of the element.
7 | * @param {boolean} flex Whether to utilize flexbox or not
8 | * @return {object} an object containing the valid JSS rules and values to
9 | * create a row.
10 | */
11 | export default function row(rowVal, gutter, flex) {
12 | const style = {
13 | width: '100%',
14 | };
15 |
16 | if (flex === true) {
17 | style.flex = '0 0 auto';
18 | }
19 |
20 | if (gutter !== '0') {
21 | style.height =
22 | `calc(99.99% * ${rowVal} - (${gutter} - ${gutter} * ${rowVal}))`;
23 | } else {
24 | style.height = `calc(99.999999% * ${rowVal})`;
25 | }
26 |
27 | style.marginBottom = gutter;
28 |
29 | style['&:last-child'] = {
30 | marginBottom: '0',
31 | };
32 |
33 | return style;
34 | }
35 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.utils.clearFix: An object containing the styles necessary to apply
3 | * a clear fix to an element.
4 | * @type {Object}
5 | */
6 | export const clearFix = {
7 | '*zoom': '1',
8 |
9 | '&:before': {
10 | content: "''",
11 | display: 'table',
12 | },
13 |
14 | '&:after': {
15 | content: "''",
16 | display: 'table',
17 | clear: 'both',
18 | },
19 | };
20 |
21 | /**
22 | * Perdido.utils.edit: An object containing the styling to apply an "edit" or
23 | * "debug" view.
24 | * @type {Object}
25 | */
26 | export const edit = {
27 | '& *:not(input):not(textarea):not(select)': {
28 | backgroundColor: 'rgba(0, 0, 255, 0.1)',
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/waffle.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Perdido.waffle: Creates a block that is a fraction of the size of its
3 | * containing element's width AND height with a gutter on
4 | * the right and bottom.
5 | *
6 | * @param {string} waffleVal This is a simple fraction of the containing
7 | * element's width and height.
8 | * @param {integer} [cycle] - Perdido works by assigning a margin-right/bottom
9 | * to all elements except the last in the row. If settings.cycle is set to
10 | * auto it will do this by default by using the denominator of the fraction
11 | * you pick. To override the default use this param.,
12 | * e.g.: {'.foo': { extend: Perdido.waffle('2/4', 2)}}
13 | * @param {length} [gutter] - how many units wide the gutter should be.
14 | * @param {boolean} flex Determines whether to use flexbox
15 | * @return {object} an object containing the valid JSS rules and values to
16 | * create a waffle grid.
17 | */
18 | export default function waffle(waffleVal, cycle, gutter, flex) {
19 | const style = {};
20 | let cycleVal;
21 |
22 | if (cycle === -1) {
23 | cycleVal = waffleVal.split('/')[1];
24 | } else {
25 | cycleVal = cycle;
26 | }
27 |
28 | if (flex === true) {
29 | style.flex = '0 0 auto';
30 |
31 | style['&:nth-child(n)'] = {
32 | marginRight: gutter,
33 | marginBottom: gutter,
34 | };
35 |
36 | style['&:last-child'] = {
37 | marginRight: '0',
38 | marginBottom: '0',
39 | };
40 |
41 | if (cycleVal !== 0) {
42 | style[`&:nth-child(${cycleVal}n)`] = {
43 | marginRight: '0',
44 | float: 'right',
45 | };
46 |
47 | style[`&:nth-last-child(-n + ${cycleVal})`] = {
48 | marginBottom: '0',
49 | };
50 | }
51 | } else {
52 | style['&:nth-child(n)'] = {
53 | float: 'left',
54 | marginRight: gutter,
55 | marginBottom: gutter,
56 | clear: 'none',
57 | };
58 |
59 | style['&:last-child'] = {
60 | marginRight: '0',
61 | marginBottom: '0',
62 | };
63 |
64 |
65 | if (cycleVal !== 0) {
66 | style[`&:nth-child(${cycleVal}n)`] = {
67 | marginRight: '0',
68 | float: 'right',
69 | };
70 | style[`&:nth-child(${cycleVal}n + 1)`] = {
71 | clear: 'left',
72 | };
73 |
74 | style[`&:nth-last-child(-n + ${cycleVal})`] = {
75 | marginBottom: '0',
76 | };
77 | }
78 | }
79 |
80 | if (gutter !== '0') {
81 | style.width =
82 | `calc(99.99% * ${waffleVal} - (${gutter} - ${gutter} * ${waffleVal}))`;
83 | style.height =
84 | `calc(99.99% * ${waffleVal} - (${gutter} - ${gutter} * ${waffleVal}))`;
85 | } else {
86 | style.width = `calc(99.999999% * ${waffleVal})`;
87 | style.height = `calc(99.999999% * ${waffleVal})`;
88 | }
89 |
90 | return style;
91 | }
92 |
--------------------------------------------------------------------------------
/tests.webpack.js:
--------------------------------------------------------------------------------
1 | const context = require.context('./tests', true, /\.js$/)
2 | context.keys().forEach(context)
3 |
--------------------------------------------------------------------------------
/tests/align-flex.js:
--------------------------------------------------------------------------------
1 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
2 | import {jssSetup, jssReset, testMethod} from './helpers';
3 |
4 | afterEach(jssReset);
5 | beforeEach(jssSetup);
6 |
7 | /* eslint-disable max-len */
8 | describe('Perdido Align Flex', () => {
9 | beforeEach(() => {
10 | perdido.gutter = '30px';
11 | perdido.flex = false;
12 | perdido.cycle = -1;
13 | perdido.offsetDir = 'row';
14 | });
15 |
16 | testMethod('can support resetting alignment', perdido.align('reset', {flex: true}), [
17 | 'a {\n display: initial;\n}',
18 | 'a > * {\n justify-content: inherit;\n align-items: inherit;\n}',
19 | ]);
20 |
21 | testMethod('can support aligning horizontally', perdido.align('horizontal', {flex: true}), [
22 | 'a {\n display: flex;\n}',
23 | 'a > * {\n justify-content: center;\n align-items: inherit;\n}',
24 | ]);
25 |
26 | testMethod('can support aligning verticaly', perdido.align('vertical', {flex: true}), [
27 | 'a {\n display: flex;\n}',
28 | 'a > * {\n justify-content: inherit;\n align-items: center;\n}',
29 | ]);
30 |
31 | testMethod('can support aligning top left', perdido.align('top-left', {flex: true}), [
32 | 'a {\n display: flex;\n}',
33 | 'a > * {\n justify-content: flex-start;\n align-items: flex-start;\n}'
34 | ]);
35 |
36 | testMethod('can support aligning top center', perdido.align('top-center', {flex: true}), [
37 | 'a {\n display: flex;\n}',
38 | 'a > * {\n justify-content: center;\n align-items: flex-start;\n}'
39 | ]);
40 |
41 | testMethod('can support aligning top', perdido.align('top', {flex: true}), [
42 | 'a {\n display: flex;\n}',
43 | 'a > * {\n justify-content: center;\n align-items: flex-start;\n}'
44 | ]);
45 |
46 | testMethod('can support aligning top right', perdido.align('top-right', {flex: true}), [
47 | 'a {\n display: flex;\n}',
48 | 'a > * {\n justify-content: flex-end;\n align-items: flex-start;\n}'
49 | ]);
50 |
51 | testMethod('can support aligning middle left', perdido.align('middle-left', {flex: true}), [
52 | 'a {\n display: flex;\n}',
53 | 'a > * {\n justify-content: flex-start;\n align-items: center;\n}'
54 | ]);
55 |
56 | testMethod('can support aligning left', perdido.align('left', {flex: true}), [
57 | 'a {\n display: flex;\n}',
58 | 'a > * {\n justify-content: flex-start;\n align-items: center;\n}'
59 | ]);
60 |
61 | testMethod('can support aligning middle center', perdido.align('middle-center', {flex: true}), [
62 | 'a {\n display: flex;\n}',
63 | 'a > * {\n justify-content: center;\n align-items: center;\n}'
64 | ]);
65 |
66 | testMethod('can support aligning center', perdido.align('center', {flex: true}), [
67 | 'a {\n display: flex;\n}',
68 | 'a > * {\n justify-content: center;\n align-items: center;\n}'
69 | ]);
70 |
71 | testMethod('can support aligning middle right', perdido.align('middle-right', {flex: true}), [
72 | 'a {\n display: flex;\n}',
73 | 'a > * {\n justify-content: flex-end;\n align-items: center;\n}'
74 | ]);
75 |
76 | testMethod('can support aligning right', perdido.align('right', {flex: true}), [
77 | 'a {\n display: flex;\n}',
78 | 'a > * {\n justify-content: flex-end;\n align-items: center;\n}'
79 | ]);
80 |
81 | testMethod('can support aligning bottom left', perdido.align('bottom-left', {flex: true}), [
82 | 'a {\n display: flex;\n}',
83 | 'a > * {\n justify-content: flex-start;\n align-items: flex-end;\n}'
84 | ]);
85 |
86 | testMethod('can support aligning bottom center', perdido.align('bottom-center', {flex: true}), [
87 | 'a {\n display: flex;\n}',
88 | 'a > * {\n justify-content: center;\n align-items: flex-end;\n}'
89 | ]);
90 |
91 | testMethod('can support aligning bottom', perdido.align('bottom', {flex: true}), [
92 | 'a {\n display: flex;\n}',
93 | 'a > * {\n justify-content: center;\n align-items: flex-end;\n}'
94 | ]);
95 |
96 | testMethod('can support aligning bottom right', perdido.align('bottom-right', {flex: true}), [
97 | 'a {\n display: flex;\n}',
98 | 'a > * {\n justify-content: flex-end;\n align-items: flex-end;\n}'
99 | ]);
100 | });
101 | /* eslint-enable max-len */
102 |
--------------------------------------------------------------------------------
/tests/align.js:
--------------------------------------------------------------------------------
1 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
2 | import {jssSetup, jssReset, testMethod} from './helpers';
3 |
4 | afterEach(jssReset);
5 | beforeEach(jssSetup);
6 |
7 | /* eslint-disable max-len */
8 | describe('Perdido Align', () => {
9 | beforeEach(() => {
10 | perdido.gutter = '30px';
11 | perdido.flex = false;
12 | perdido.cycle = -1;
13 | perdido.offsetDir = 'row';
14 | });
15 |
16 | testMethod('can support resetting alignment', perdido.align('reset'), [
17 | 'a {\n position: static;\n}',
18 | 'a > * {\n position: static;\n top: auto;\n right: auto;\n bottom: auto;',
19 | ' left: auto;\n transform: translate(0, 0);\n}'
20 | ]);
21 |
22 | testMethod('can support aligning horizontally', perdido.align('horizontal'), [
23 | 'a {\n position: relative;\n}',
24 | 'a > * {\n position: absolute;\n top: auto;\n right: auto;\n bottom: auto;',
25 | ' left: 50%;\n transform: translate(-50%, 0);\n}'
26 | ]);
27 |
28 | testMethod('can support aligning verticaly', perdido.align('vertical'), [
29 | 'a {\n position: relative;\n}',
30 | 'a > * {\n position: absolute;\n top: 50%;\n right: auto;\n bottom: auto;',
31 | ' left: auto;\n transform: translate(0, -50%);\n}'
32 | ]);
33 |
34 | testMethod('can support aligning top left', perdido.align('top-left'), [
35 | 'a {\n position: relative;\n}',
36 | 'a > * {\n position: absolute;\n top: 0;\n right: auto;\n bottom: auto;',
37 | ' left: 0;\n transform: translate(0, 0);\n}'
38 | ]);
39 |
40 | testMethod('can support aligning top center', perdido.align('top-center'), [
41 | 'a {\n position: relative;\n}',
42 | 'a > * {\n position: absolute;\n top: 0;\n right: auto;\n bottom: auto;',
43 | ' left: 50%;\n transform: translate(-50%, 0);\n}'
44 | ]);
45 |
46 | testMethod('can support aligning top', perdido.align('top'), [
47 | 'a {\n position: relative;\n}',
48 | 'a > * {\n position: absolute;\n top: 0;\n right: auto;\n bottom: auto;',
49 | ' left: 50%;\n transform: translate(-50%, 0);\n}'
50 | ]);
51 |
52 | testMethod('can support aligning top right', perdido.align('top-right'), [
53 | 'a {\n position: relative;\n}',
54 | 'a > * {\n position: absolute;\n top: 0;\n right: 0;\n bottom: auto;',
55 | ' left: auto;\n transform: translate(0, 0);\n}'
56 | ]);
57 |
58 | testMethod('can support aligning middle left', perdido.align('middle-left'), [
59 | 'a {\n position: relative;\n}',
60 | 'a > * {\n position: absolute;\n top: 50%;\n right: auto;\n bottom: auto;',
61 | ' left: 0;\n transform: translate(0, -50%);\n}'
62 | ]);
63 |
64 | testMethod('can support aligning left', perdido.align('left'), [
65 | 'a {\n position: relative;\n}',
66 | 'a > * {\n position: absolute;\n top: 50%;\n right: auto;\n bottom: auto;',
67 | ' left: 0;\n transform: translate(0, -50%);\n}'
68 | ]);
69 |
70 | testMethod('can support aligning middle center', perdido.align('middle-center'), [
71 | 'a {\n position: relative;\n}',
72 | 'a > * {\n position: absolute;\n top: 50%;\n right: auto;\n bottom: auto;',
73 | ' left: 50%;\n transform: translate(-50%, -50%);\n}'
74 | ]);
75 |
76 | testMethod('can support aligning center', perdido.align('center'), [
77 | 'a {\n position: relative;\n}',
78 | 'a > * {\n position: absolute;\n top: 50%;\n right: auto;\n bottom: auto;',
79 | ' left: 50%;\n transform: translate(-50%, -50%);\n}'
80 | ]);
81 |
82 | testMethod('can support aligning middle right', perdido.align('middle-right'), [
83 | 'a {\n position: relative;\n}',
84 | 'a > * {\n position: absolute;\n top: 50%;\n right: 0;\n bottom: auto;',
85 | ' left: auto;\n transform: translate(0, -50%);\n}'
86 | ]);
87 |
88 | testMethod('can support aligning right', perdido.align('right'), [
89 | 'a {\n position: relative;\n}',
90 | 'a > * {\n position: absolute;\n top: 50%;\n right: 0;\n bottom: auto;',
91 | ' left: auto;\n transform: translate(0, -50%);\n}'
92 | ]);
93 |
94 | testMethod('can support aligning bottom left', perdido.align('bottom-left'), [
95 | 'a {\n position: relative;\n}',
96 | 'a > * {\n position: absolute;\n top: auto;\n right: auto;\n bottom: 0;',
97 | ' left: 0;\n transform: translate(0, 0);\n}'
98 | ]);
99 |
100 | testMethod('can support aligning bottom center', perdido.align('bottom-center'), [
101 | 'a {\n position: relative;\n}',
102 | 'a > * {\n position: absolute;\n top: auto;\n right: auto;\n bottom: 0;',
103 | ' left: 50%;\n transform: translate(-50%, 0);\n}'
104 | ]);
105 |
106 | testMethod('can support aligning bottom', perdido.align('bottom'), [
107 | 'a {\n position: relative;\n}',
108 | 'a > * {\n position: absolute;\n top: auto;\n right: auto;\n bottom: 0;',
109 | ' left: 50%;\n transform: translate(-50%, 0);\n}'
110 | ]);
111 |
112 | testMethod('can support aligning bottom right', perdido.align('bottom-right'), [
113 | 'a {\n position: relative;\n}',
114 | 'a > * {\n position: absolute;\n top: auto;\n right: 0;\n bottom: 0;',
115 | ' left: auto;\n transform: translate(0, 0);\n}'
116 | ]);
117 | });
118 | /* eslint-enable max-len */
119 |
--------------------------------------------------------------------------------
/tests/center.js:
--------------------------------------------------------------------------------
1 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
2 | import {jssSetup, jssReset, testMethod} from './helpers';
3 |
4 | afterEach(jssReset);
5 | beforeEach(jssSetup);
6 |
7 | /* eslint-disable max-len */
8 | describe('Perdido Center', () => {
9 | beforeEach(() => {
10 | perdido.gutter = '30px';
11 | perdido.flex = false;
12 | perdido.cycle = -1;
13 | perdido.offsetDir = 'row';
14 | });
15 |
16 | testMethod('can support horizontal centering containers', perdido.center('980px'), [
17 | 'a {\n max-width: 980px;\n margin-left: auto;\n margin-right: auto;\n}',
18 | 'a:before {\n content: \'\';\n display: table;\n}',
19 | 'a:after {\n content: \'\';\n display: table;\n clear: both;\n}'
20 | ]);
21 |
22 | testMethod('can support adding 30px padding', perdido.center('980px', {padding: '30px'}), [
23 | 'a {\n max-width: 980px;\n margin-left: auto;\n margin-right: auto;',
24 | ' padding-left: 30px;\n padding-right: 30px;\n}',
25 | 'a:before {\n content: \'\';\n display: table;\n}',
26 | 'a:after {\n content: \'\';\n display: table;\n clear: both;\n}'
27 | ]);
28 |
29 | testMethod('can support flexbox', perdido.center('1140px', {padding: '30px', flex: true}), [
30 | 'a {\n max-width: 1140px;\n margin-left: auto;\n margin-right: auto;',
31 | ' padding-left: 30px;\n padding-right: 30px;\n display: flex;',
32 | ' flex-flow: row wrap;\n}'
33 | ]);
34 | });
35 | /* eslint-enable max-len */
36 |
--------------------------------------------------------------------------------
/tests/column.js:
--------------------------------------------------------------------------------
1 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
2 | import {jssSetup, jssReset, testMethod} from './helpers';
3 |
4 | afterEach(jssReset);
5 | beforeEach(jssSetup);
6 |
7 | /* eslint-disable max-len */
8 | describe('Perdido Column', () => {
9 | testMethod('can support 3 column layout', perdido.column('1/3'), [
10 | 'a {\n width: calc(99.99% * 1/3 - (30px - 30px * 1/3));\n}',
11 | 'a:nth-child(n) {\n float: left;\n margin-right: 30px;\n clear: none;\n}',
12 | 'a:last-child {\n margin-right: 0;\n}',
13 | 'a:nth-child(3n) {\n float: right;\n margin-right: 0;\n}',
14 | 'a:nth-child(3n + 1) {\n clear: left;\n}'
15 | ]);
16 |
17 | testMethod('can support 2/5 column layout', perdido.column('2/5'), [
18 | 'a {\n width: calc(99.99% * 2/5 - (30px - 30px * 2/5));\n}',
19 | 'a:nth-child(n) {\n float: left;\n margin-right: 30px;\n clear: none;\n}',
20 | 'a:last-child {\n margin-right: 0;\n}',
21 | 'a:nth-child(5n) {\n float: right;\n margin-right: 0;\n}',
22 | 'a:nth-child(5n + 1) {\n clear: left;\n}'
23 | ]);
24 |
25 | testMethod('can support custom cycle', perdido.column('2/4', {cycle: 2}), [
26 | 'a {\n width: calc(99.99% * 2/4 - (30px - 30px * 2/4));\n}',
27 | 'a:nth-child(n) {\n float: left;\n margin-right: 30px;\n clear: none;\n}',
28 | 'a:last-child {\n margin-right: 0;\n}',
29 | 'a:nth-child(2n) {\n float: right;\n margin-right: 0;\n}',
30 | 'a:nth-child(2n + 1) {\n clear: left;\n}'
31 | ]);
32 |
33 | testMethod('can support no gutter', perdido.column('2/5', {cycle: 3, gutter: '0'}), [
34 | 'a {\n width: calc(99.999999% * 2/5);\n}',
35 | 'a:nth-child(n) {\n float: left;\n margin-right: 0;\n clear: none;\n}',
36 | 'a:last-child {\n margin-right: 0;\n}',
37 | 'a:nth-child(3n) {\n float: right;\n margin-right: 0;\n}',
38 | 'a:nth-child(3n + 1) {\n clear: left;\n}'
39 | ]);
40 |
41 | testMethod('can support flexbox', perdido.column('2/6', {cycle: 3, gutter: '60px', flex: true}), [
42 | 'a {\n width: calc(99.99% * 2/6 - (60px - 60px * 2/6));\n flex: 0 0 auto;\n}',
43 | 'a:nth-child(n) {\n margin-right: 60px;\n}',
44 | 'a:last-child {\n margin-right: 0;\n}',
45 | 'a:nth-child(3n) {\n float: right;\n margin-right: 0;\n}'
46 | ]);
47 |
48 | testMethod('can support none rule', perdido.column('none'), [
49 | 'a {\n width: auto;\n}',
50 | 'a:last-child {\n float: none;\n clear: none;\n margin-right: 0;\n width: auto;\n}',
51 | 'a:nth-child(n) {\n float: none;\n clear: none;\n margin-right: 0;\n width: auto;\n}',
52 | 'a:nth-child(1n + 1) {\n float: none;\n clear: none;\n margin-right: 0;\n width: auto;\n}',
53 | 'a:nth-child(1n) {\n float: none;\n clear: none;\n margin-right: 0;\n width: auto;\n}'
54 | ]);
55 | });
56 | /* eslint-enable max-len */
57 |
--------------------------------------------------------------------------------
/tests/creation.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect.js';
2 | import Perdido from '../src/perdido'; // eslint-disable-line import/no-unresolved
3 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
4 | import {jssSetup, jssReset} from './helpers';
5 |
6 | afterEach(jssReset);
7 | beforeEach(jssSetup);
8 |
9 | /* eslint-disable max-len */
10 | describe('Perdido Creation', () => {
11 | it('should export a Perdido instance', () => {
12 | expect(perdido).to.be.a(Perdido);
13 | expect(perdido).not.to.be(null);
14 | });
15 |
16 | it('create bare default Perdido', () => {
17 | const testPerdido = perdido.create();
18 | expect(testPerdido.gutter).to.be('30px');
19 | expect(testPerdido.flex).to.be(false);
20 | expect(testPerdido.cycle).to.be(-1);
21 | expect(testPerdido.offsetDir).to.be('row');
22 | });
23 |
24 | it('create Perdido with one override', () => {
25 | const testPerdido = perdido.create({gutter: '60px'});
26 | expect(testPerdido.gutter).to.be('60px');
27 | expect(testPerdido.flex).to.be(false);
28 | expect(testPerdido.cycle).to.be(-1);
29 | expect(testPerdido.offsetDir).to.be('row');
30 | });
31 |
32 | it('create Perdido with two overrides', () => {
33 | const testPerdido = perdido.create({gutter: '40em', flex: true});
34 | expect(testPerdido.gutter).to.be('40em');
35 | expect(testPerdido.flex).to.be(true);
36 | expect(testPerdido.cycle).to.be(-1);
37 | expect(testPerdido.offsetDir).to.be('row');
38 | });
39 |
40 | it('create Perdido with two out of order overrides', () => {
41 | const testPerdido = perdido.create({gutter: '40em', cycle: 6});
42 | expect(testPerdido.gutter).to.be('40em');
43 | expect(testPerdido.flex).to.be(false);
44 | expect(testPerdido.cycle).to.be(6);
45 | expect(testPerdido.offsetDir).to.be('row');
46 | });
47 |
48 | it('create Perdido with three overrides', () => {
49 | const testPerdido = perdido.create({gutter: '80em', flex: true, cycle: 3});
50 | expect(testPerdido.gutter).to.be('80em');
51 | expect(testPerdido.flex).to.be(true);
52 | expect(testPerdido.cycle).to.be(3);
53 | expect(testPerdido.offsetDir).to.be('row');
54 | });
55 |
56 | it('create Perdido with four overrides', () => {
57 | const testPerdido = perdido.create({gutter: '75rem', flex: true, cycle: 3,
58 | offsetDir: 'column'});
59 | expect(testPerdido.gutter).to.be('75rem');
60 | expect(testPerdido.flex).to.be(true);
61 | expect(testPerdido.cycle).to.be(3);
62 | expect(testPerdido.offsetDir).to.be('column');
63 | });
64 | });
65 |
66 | /* eslint-enable max-len */
67 |
--------------------------------------------------------------------------------
/tests/flex-container.js:
--------------------------------------------------------------------------------
1 | import perdido from 'perdido'; // eslint-disable-line import/no-unresolved
2 | import {jssSetup, jssReset, testMethod} from './helpers';
3 |
4 | afterEach(jssReset);
5 | beforeEach(jssSetup);
6 |
7 | /* eslint-disable max-len */
8 | describe('Perdido FlexContainer', () => {
9 | testMethod('can support flex for row', perdido.flexContainer('row'), [
10 | 'a {\n display: flex;\n flex-flow: row wrap;\n}'
11 | ]);
12 |
13 | testMethod('can support flex for column', perdido.flexContainer('column'), [
14 | 'a {\n display: flex;\n flex-flow: column nowrap;\n}'
15 | ]);
16 | });
17 | /* eslint-enable max-len */
18 |
--------------------------------------------------------------------------------
/tests/helpers.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect.js';
2 | import jss from 'jss';
3 | import jssExtend from 'jss-extend';
4 | import jssNested from 'jss-nested';
5 | import jssCamelCase from 'jss-camel-case';
6 | import jssDefaultUnit from 'jss-default-unit';
7 | import jssVendorPrefixer from 'jss-vendor-prefixer'; // eslint-disable-line import/no-unresolved
8 |
9 | export function jssReset() {
10 | jss.plugins.registry = [];
11 | jss.sheets.registry = [];
12 | jss.uid.reset();
13 | }
14 |
15 | export function jssSetup() {
16 | jss.use(jssExtend());
17 | jss.use(jssNested());
18 | jss.use(jssCamelCase());
19 | jss.use(jssDefaultUnit());
20 | jss.use(jssVendorPrefixer());
21 | }
22 |
23 | export function testMethod(testName, method, testStrs) {
24 | return it(testName, () => {
25 | const sheet = jss.createStyleSheet({
26 | a: {
27 | extend: method,
28 | },
29 | }, {named: false});
30 | expect(sheet.toString()).to.be(testStrs.join('\n'));
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |