├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package.json └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{*.{md,yml},package.json}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | yarn.lock 4 | yarn-error.log 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '8' 5 | 6 | cache: 7 | directories: 8 | - node_modules 9 | 10 | before_install: 11 | - npm update 12 | 13 | install: 14 | - npm install 15 | 16 | script: 17 | - npm test 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## 1.1.0 - 2019-04-16 6 | 7 | ### Added 8 | 9 | - Added tests. - Thanks @opdavies. 10 | 11 | ### Changed 12 | 13 | - Updated readme. 14 | 15 | ### Removed 16 | 17 | - Removed lock files from version control. 18 | 19 | ## 1.0.0 - 2018-05-04 20 | 21 | ### Added 22 | 23 | - Added ability to name values. 24 | - You can now define a range of numbers to generate. 25 | 26 | ### Changed 27 | 28 | - First argument should now be an object instead of array. 29 | 30 | ### Removed 31 | 32 | - Removed second argument. Define as an array under the `variants` key in options object instead. Default is still `['responsive']`. 33 | 34 | ## 0.2.0 - 2018-03-21 35 | 36 | ### Added 37 | 38 | - Added CHANGELOG. 39 | 40 | ### Changed 41 | 42 | - Updated README. 43 | 44 | ## 0.1.2 - 2018-03-21 45 | 46 | ### Removed 47 | 48 | - Remove and add `package-lock.json` to `.gitignore`. 49 | 50 | ## 0.1.1 - 2018-03-21 51 | 52 | ### Changed 53 | 54 | - Just a version bump to fix the release on npm. 55 | 56 | ## 0.1.0 - 2018-03-20 57 | 58 | - Initial release. 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 035 Media Group 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flexbox Order - TailwindCSS Plugin 2 | 3 | [![npm version](https://img.shields.io/npm/v/tailwindcss-flexbox-order.svg)](https://www.npmjs.com/package/tailwindcss-flexbox-order) 4 | [![npm downloads](https://img.shields.io/npm/dt/tailwindcss-flexbox-order.svg)](https://www.npmjs.com/package/tailwindcss-flexbox-order) 5 | [![Build Status](https://travis-ci.com/035media/tailwindcss-flexbox-order.svg?branch=master)](https://travis-ci.com/035media/tailwindcss-flexbox-order) 6 | 7 | This plugin generates classes for ordering flexbox and grid items using `order: #;`. 8 | 9 | ## Installation 10 | 11 | Pull it in through npm: 12 | 13 | ```bash 14 | npm install --save-dev tailwindcss-flexbox-order 15 | ``` 16 | 17 | ## Usage 18 | 19 | To get going with some sensible defaults you don't have to pass any options.\ 20 | Just add it to the plugins array of your Tailwind config. 21 | 22 | ```js 23 | plugins: [ 24 | // Other plugins 25 | require('tailwindcss-flexbox-order')(), 26 | ], 27 | ``` 28 | 29 | By default the plugin generates the following classes, with all of their responsive variants: 30 | 31 | ```css 32 | .-order-1 { order: -1; } 33 | .order-0 { order: 0; } 34 | .order-1 { order: 1; } 35 | .order-2 { order: 2; } 36 | .order-3 { order: 3; } 37 | .order-4 { order: 4; } 38 | .order-5 { order: 5; } 39 | ``` 40 | 41 | ### Options 42 | 43 | You can pass an object to override the default settings. 44 | 45 | ```js 46 | // Default options 47 | { 48 | range: { 49 | from: -1, 50 | to: 5, 51 | }, 52 | values: false, 53 | variants: ['responsive'], 54 | } 55 | ``` 56 | 57 | #### range 58 | 59 | Range takes an object with `from` and `to` keys with integer values and generates them and every number in between. 60 | 61 | The default option is `{ from: -1, to: 5 }`. 62 | 63 | ```js 64 | range: { 65 | from: -2, 66 | to: 2, 67 | }, 68 | ``` 69 | 70 | ```css 71 | .-order-2 { order: -2; } 72 | .-order-1 { order: -1; } 73 | .order-0 { order: 0; } 74 | .order-1 { order: 1; } 75 | .order-2 { order: 2; } 76 | ``` 77 | 78 | Setting range to `false` disables range generation. 79 | 80 | ```js 81 | range: false, 82 | ``` 83 | 84 | #### values 85 | 86 | Values can be an object with key/value pairs.\ 87 | Your strings are automatically escaped. 88 | 89 | The default option is `false`. 90 | 91 | ```js 92 | values: { 93 | 'first': -999, 94 | 'last': 999, 95 | '$p3ci@l': 1337, 96 | } 97 | ``` 98 | 99 | ```css 100 | .order-first { order: -999; } 101 | .order-last { order: 999; } 102 | .order-\$p3ci\@l { order: 1337; } 103 | ``` 104 | 105 | Or it can take an array of integers. 106 | 107 | ```js 108 | values: [-10, 0, 10, 20], 109 | ``` 110 | 111 | ```css 112 | .-order-10 { order: -10; } 113 | .order-0 { order: 0; } 114 | .order-10 { order: 10; } 115 | .order-20 { order: 20; } 116 | ``` 117 | 118 | #### variants 119 | 120 | Variants can be set to an array with any of the supported Tailwind variants. 121 | 122 | The default option is `['responsive']`. 123 | 124 | ```js 125 | variants: ['responsive', 'hover', 'focus', 'active', 'group-hover'] 126 | ``` 127 | 128 | ## Upgrading from 0.1 or 0.2 129 | 130 | Earlier versions took an array of integers as the first argument, and another array of variants as the second argument. 131 | 132 | Starting at 1.0, all options should be passed as a plain object. 133 | 134 | ```js 135 | // OLD - 0.x 136 | require('tailwindcss-flexbox-order')([-1, 1, 5, 10], ['responsive']) 137 | 138 | // NEW - 1.x 139 | require('tailwindcss-flexbox-order')({ 140 | range: false, 141 | values: [-1, 1, 5, 10], 142 | variants: ['responsive'], 143 | }) 144 | ``` 145 | 146 | All versions will still generate the same output if no options are passed. 147 | 148 | ## License 149 | 150 | This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). 151 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let _ = require('lodash'); 2 | 3 | module.exports = function (options = {}) { 4 | return function ({ addUtilities, e }) { 5 | const defaultOptions = { 6 | range: { 7 | from: -1, 8 | to: 5, 9 | }, 10 | values: false, 11 | variants: ['responsive'], 12 | }; 13 | 14 | options = _.defaults(options, defaultOptions); 15 | 16 | if (_.isEmpty(options.range) || ! _.isPlainObject(options.range)) { 17 | options.range = false; 18 | } 19 | 20 | if ( 21 | _.isEmpty(options.values) 22 | && ( 23 | ! _.isPlainObject(options.values) 24 | || ! _.isArray(options.values) 25 | ) 26 | ) { 27 | options.values = false; 28 | } 29 | 30 | if ( 31 | _.has(options.range, 'from') 32 | && _.has(options.range, 'to') 33 | && options.range.from < options.range.to 34 | ) { 35 | const range = _.map(_.range(options.range.from, ++options.range.to), value => { 36 | return generateOutput(value); 37 | }); 38 | 39 | addUtilities(range, options.variants); 40 | } 41 | 42 | if (_.isPlainObject(options.values)) { 43 | const values = _.map(options.values, (value, key) => { 44 | return generateOutput(value, key); 45 | }); 46 | 47 | addUtilities(values, options.variants); 48 | } else if (_.isArray(options.values)) { 49 | const values = _.map(options.values, value => { 50 | return generateOutput(value); 51 | }); 52 | 53 | addUtilities(values, options.variants); 54 | } 55 | 56 | function generateOutput(value, key) { 57 | value = _.toSafeInteger(value); 58 | 59 | if (key === undefined) { 60 | key = value; 61 | 62 | return (value < 0) 63 | ? { [`.-order-${-key}`]: { order: value } } 64 | : { [`.order-${key}`]: { order: value } }; 65 | } else { 66 | return { [`.${e('order-'+key)}`]: { order: value } }; 67 | } 68 | } 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss-flexbox-order", 3 | "version": "1.1.0", 4 | "description": "Generate utility classes to easily order flex-items", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/035media/tailwindcss-flexbox-order.git" 9 | }, 10 | "keywords": [ 11 | "tailwind", 12 | "tailwindcss", 13 | "tailwind css", 14 | "tailwindcss-plugin", 15 | "plugin", 16 | "flexbox", 17 | "flex", 18 | "order" 19 | ], 20 | "author": "035 Media Group", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/035media/tailwindcss-flexbox-order/issues" 24 | }, 25 | "homepage": "https://github.com/035media/tailwindcss-flexbox-order#readme", 26 | "dependencies": { 27 | "lodash": "^4.17.11", 28 | "postcss": "^7.0.14", 29 | "tailwindcss": "^1.0.0-beta.4" 30 | }, 31 | "devDependencies": { 32 | "jest": "^24.7.1", 33 | "jest-matcher-css": "^1.0.3" 34 | }, 35 | "scripts": { 36 | "test": "jest" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const plugin = require('./index'); 3 | const postcss = require('postcss'); 4 | const tailwindcss = require('tailwindcss'); 5 | const cssMatcher = require('jest-matcher-css'); 6 | const defaultConfig = require('tailwindcss/defaultConfig'); 7 | 8 | const generatePluginCss = (options = {}) => { 9 | return postcss( 10 | tailwindcss({ 11 | corePlugins: disableCorePlugins(), 12 | plugins: [plugin(options)], 13 | theme: { 14 | screens: _.pick(defaultConfig.theme.screens, 'lg'), 15 | }, 16 | })) 17 | .process('@tailwind utilities;', { 18 | from: undefined, 19 | }) 20 | .then(result => { 21 | return result.css; 22 | }); 23 | } 24 | 25 | const disableCorePlugins = () => { 26 | return _.mapValues(defaultConfig.variants, () => false); 27 | } 28 | 29 | expect.extend({ 30 | toMatchCss: cssMatcher, 31 | }); 32 | 33 | test('it generates the default order classes', () => { 34 | return generatePluginCss().then(css => { 35 | expect(css).toMatchCss(` 36 | .-order-1 { 37 | order: -1; 38 | } 39 | 40 | .order-0 { 41 | order: 0; 42 | } 43 | 44 | .order-1 { 45 | order: 1; 46 | } 47 | 48 | .order-2 { 49 | order: 2; 50 | } 51 | 52 | .order-3 { 53 | order: 3; 54 | } 55 | 56 | .order-4 { 57 | order: 4; 58 | } 59 | 60 | .order-5 { 61 | order: 5; 62 | } 63 | 64 | @media (min-width: 1024px) { 65 | .lg\\:-order-1 { 66 | order: -1; 67 | } 68 | 69 | .lg\\:order-0 { 70 | order: 0; 71 | } 72 | 73 | .lg\\:order-1 { 74 | order: 1; 75 | } 76 | 77 | .lg\\:order-2 { 78 | order: 2; 79 | } 80 | 81 | .lg\\:order-3 { 82 | order: 3; 83 | } 84 | 85 | .lg\\:order-4 { 86 | order: 4; 87 | } 88 | 89 | .lg\\:order-5 { 90 | order: 5; 91 | } 92 | } 93 | `); 94 | }); 95 | }); 96 | 97 | test('it generates order classes by defining a range', () => { 98 | const range = { 99 | from: -2, 100 | to: 1, 101 | }; 102 | 103 | return generatePluginCss({ range }).then(css => { 104 | expect(css).toMatchCss(` 105 | .-order-2 { 106 | order: -2; 107 | } 108 | 109 | .-order-1 { 110 | order: -1; 111 | } 112 | 113 | .order-0 { 114 | order: 0; 115 | } 116 | 117 | .order-1 { 118 | order: 1; 119 | } 120 | 121 | @media (min-width: 1024px) { 122 | .lg\\:-order-2 { 123 | order: -2; 124 | } 125 | 126 | .lg\\:-order-1 { 127 | order: -1; 128 | } 129 | 130 | .lg\\:order-0 { 131 | order: 0; 132 | } 133 | 134 | .lg\\:order-1 { 135 | order: 1; 136 | } 137 | } 138 | `); 139 | }); 140 | }); 141 | 142 | test('it generates order classes by defining values', () => { 143 | const range = false; 144 | const values = [-10, 0, 10, 20]; 145 | 146 | return generatePluginCss({ range, values }).then(css => { 147 | expect(css).toMatchCss(` 148 | .-order-10 { 149 | order: -10; 150 | } 151 | 152 | .order-0 { 153 | order: 0; 154 | } 155 | 156 | .order-10 { 157 | order: 10; 158 | } 159 | 160 | .order-20 { 161 | order: 20; 162 | } 163 | 164 | @media (min-width: 1024px) { 165 | .lg\\:-order-10 { 166 | order: -10; 167 | } 168 | 169 | .lg\\:order-0 { 170 | order: 0; 171 | } 172 | 173 | .lg\\:order-10 { 174 | order: 10; 175 | } 176 | 177 | .lg\\:order-20 { 178 | order: 20; 179 | } 180 | } 181 | `); 182 | }); 183 | }); 184 | 185 | test('it generates order classes by defining named values', () => { 186 | const range = false; 187 | const values = { 188 | 'first': -999, 189 | 'last': 999, 190 | '$p3c:@l': 1337, 191 | }; 192 | 193 | return generatePluginCss({ range, values }).then(css => { 194 | expect(css).toMatchCss(` 195 | .order-first { 196 | order: -999; 197 | } 198 | 199 | .order-last { 200 | order: 999; 201 | } 202 | 203 | .order-\\$p3c\\:\\@l { 204 | order: 1337; 205 | } 206 | 207 | @media (min-width: 1024px) { 208 | .lg\\:order-first { 209 | order: -999; 210 | } 211 | 212 | .lg\\:order-last { 213 | order: 999; 214 | } 215 | 216 | .lg\\:order-\\$p3c\\:\\@l { 217 | order: 1337; 218 | } 219 | } 220 | `); 221 | }); 222 | }); 223 | --------------------------------------------------------------------------------