├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .release-it.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── prettier.config.js ├── test.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .next 2 | out 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "es6": true, 6 | "commonjs": true 7 | }, 8 | "plugins": ["react"], 9 | "extends": [ 10 | "eslint:recommended", 11 | "plugin:react/recommended", 12 | "plugin:prettier/recommended" 13 | ], 14 | "settings": { 15 | "react": { 16 | "version": "detect" // React version. "detect" automatically picks the version you have installed. 17 | // You can also use `16.0`, `16.3`, etc, if you want to override the detected value. 18 | // default to latest and warns if missing 19 | // It will default to "detect" in the future 20 | }, 21 | "import/resolver": { 22 | "node": { 23 | "paths": ["./"] 24 | } 25 | } 26 | }, 27 | "parser": "babel-eslint", 28 | "parserOptions": { 29 | "ecmaVersion": 6, 30 | "sourceType": "module", 31 | "ecmaFeatures": { 32 | "jsx": true, 33 | "experimentalObjectRestSpread": true, 34 | "modules": true 35 | } 36 | }, 37 | "rules": { 38 | "react/prefer-stateless-function": 0, 39 | "linebreak-style": 0, 40 | "jsx-a11y/heading-has-content": 0, 41 | "jsx-a11y/href-no-hash": 0, 42 | "jsx-a11y/anchor-is-valid": 0, 43 | "no-underscore-dangle": 0, 44 | "react/no-find-dom-node": 0, 45 | "react/prop-types": 0, 46 | "no-nested-ternary": 0 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "git": { 3 | "tagName": "v${version}", 4 | "requireCleanWorkingDir": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "[javascript]": { 4 | "editor.defaultFormatter": "esbenp.prettier-vscode", 5 | "editor.formatOnSave": true 6 | }, 7 | "editor.codeActionsOnSave": { 8 | "source.fixAll.eslint": true 9 | } 10 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). 9 | 10 | ## [v1.0.2](https://github.com/robksawyer/tailwindcss-pixel-dimensions/compare/v1.0.1...v1.0.2) - 2020-07-22 11 | 12 | ### Commits 13 | 14 | - Updated README [`11d7d89`](https://github.com/robksawyer/tailwindcss-pixel-dimensions/commit/11d7d8978a69e52a85f0da986d8682d36aed9eb5) 15 | 16 | ## v1.0.1 - 2020-07-22 17 | 18 | ### Commits 19 | 20 | - Initial release [`0899011`](https://github.com/robksawyer/tailwindcss-pixel-dimensions/commit/08990110273d68951eb1ebc6e990a21038891944) 21 | - Release 1.0.1 [`01dd012`](https://github.com/robksawyer/tailwindcss-pixel-dimensions/commit/01dd012aea13aad8346326e12bda8971db38f1bd) 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # ISC License 2 | 3 | Copyright (c) Rob Sawyer 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixel Dimensions for Tailwind CSS 2 | This plugin allows you to quickly generate widths and heights in pixels. 3 | 4 | ## Requirements 5 | 6 | This plugin requires Tailwind CSS 1.2 or later. 7 | 8 | ## Installation 9 | 10 | ```bash 11 | yarn add tailwindcss-pixel-dimensions 12 | ``` 13 | 14 | ## Usage 15 | 16 | The following plugin options are available. See below how these are passed (via an object) to the plugin in your `tailwind.config.js`. 17 | 18 | ## Options Available 19 | Pass along a number value to generate that many font sizes. 20 | 21 | ```js 22 | // tailwind.config.js 23 | module.exports = { 24 | plugins: [ 25 | // Generates 10 widths and heights in pxs 26 | require('tailwindcss-pixel-dimensions')({ 27 | width: { 28 | total: 10, // 900 is the default 29 | // startingSize: 0, // default 30 | }, 31 | height: { 32 | total: 10, // 900 is the default 33 | // startingSize: 0, // default 34 | }, 35 | }), 36 | ], 37 | }; 38 | ``` 39 | 40 | The above configuration would generate the following CSS: 41 | 42 | ```css 43 | .w-0px { 44 | width: 0; 45 | } 46 | 47 | .w-1px { 48 | width: 1px; 49 | } 50 | 51 | .w-2px { 52 | width: 2px; 53 | } 54 | 55 | .w-3px { 56 | width: 3px; 57 | } 58 | 59 | .w-4px { 60 | width: 4px; 61 | } 62 | 63 | .w-5px { 64 | width: 5px; 65 | } 66 | 67 | .w-6px { 68 | width: 6px; 69 | } 70 | 71 | .w-7px { 72 | width: 7px; 73 | } 74 | 75 | .w-8px { 76 | width: 8px; 77 | } 78 | 79 | .w-9px { 80 | width: 9px; 81 | } 82 | 83 | .w-10px { 84 | width: 10px; 85 | } 86 | 87 | .h-0px { 88 | height: 0; 89 | } 90 | 91 | .h-1px { 92 | height: 1px; 93 | } 94 | 95 | .h-2px { 96 | height: 2px; 97 | } 98 | 99 | .h-3px { 100 | height: 3px; 101 | } 102 | 103 | .h-4px { 104 | height: 4px; 105 | } 106 | 107 | .h-5px { 108 | height: 5px; 109 | } 110 | 111 | .h-6px { 112 | height: 6px; 113 | } 114 | 115 | .h-7px { 116 | height: 7px; 117 | } 118 | 119 | .h-8px { 120 | height: 8px; 121 | } 122 | 123 | .h-9px { 124 | height: 9px; 125 | } 126 | 127 | .h-10px { 128 | height: 10px; 129 | } 130 | /* etc. */ 131 | ``` 132 | 133 | Which you can then use in your HTML like this: 134 | 135 | ```html 136 |
137 | I'm a div with a height of 10 pixels or pickles depending on how you pronounce it. 138 |
139 | ``` 140 | 141 | The above depends on the order of the generated CSS. 142 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TailwindCSS Font Sizes 3 | * Generates font sizes in ems 4 | * @file index.js 5 | */ 6 | const plugin = require('tailwindcss/plugin') 7 | const _ = require('lodash') 8 | // const selectorParser = require('postcss-selector-parser') 9 | 10 | /** 11 | * getSizes 12 | * Handles getting sizes in pixels 13 | * @param {int} totalSizes 14 | * @param {int} startingValue 15 | * @return {object} 16 | */ 17 | const getSizes = (totalSizes = 900, startingValue = 0) => { 18 | // The following generates an array of increasing values from the totalSizes above. 19 | const sizeArray = Array.from(Array(startingValue + totalSizes + 1).keys()) 20 | const sliced = sizeArray.slice(startingValue, sizeArray.length) 21 | // Traverse the array and generate sizes in pxs. 22 | const sizes = sliced.map((i, x) => 23 | x > 0 ? { [`${x}px`]: `${x}px;` } : { [`${x}px`]: `${x};` } 24 | ) 25 | // Merge the array of objects into a single one 26 | const sizeObj = Object.assign.apply(Object, sizes) 27 | // console.log('sizeObj', sizeObj) 28 | return sizeObj 29 | } 30 | 31 | module.exports = plugin.withOptions( 32 | function (options) { 33 | return function ({ addUtilities, e, variants, theme }) { 34 | // ... 35 | } 36 | }, 37 | function (options) { 38 | // Widths 39 | // Option defaults 40 | // { 41 | // total: 900, 42 | // startingSize: 0, 43 | // } 44 | const widths = getSizes( 45 | (options && options.width && options.width.total) || 900, 46 | (options && options.width && options.width.startingSize) || 0 47 | ) 48 | const heights = getSizes( 49 | (options && options.height && options.height.total) || 900, 50 | (options && options.height && options.height.startingSize) || 0 51 | ) 52 | return { 53 | theme: { 54 | // fontSizes: { 55 | extend: { 56 | width: { 57 | ...widths, 58 | }, 59 | height: { 60 | ...heights, 61 | }, 62 | }, 63 | }, 64 | // variants: { 65 | // fontSizes: [], 66 | // }, 67 | } 68 | } 69 | ) 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss-pixel-dimensions", 3 | "version": "1.0.2", 4 | "description": "Tailwind CSS plugin that generates widths and heights in pixels for tricky pixel-perfect layouts.", 5 | "author": "Rob Sawyer ", 6 | "license": "ISC", 7 | "repository": "https://github.com/robksawyer/tailwindcss-pixel-dimensions.git", 8 | "bugs": "https://github.com/robksawyer/tailwindcss-pixel-dimensions/issues", 9 | "homepage": "https://github.com/robksawyer/tailwindcss-pixel-dimensions", 10 | "scripts": { 11 | "test": "jest --watchAll", 12 | "version": "auto-changelog -p && git add CHANGELOG.md", 13 | "release": "f(){ release-it $1 && github-release-from-changelog ;};f" 14 | }, 15 | "auto-changelog": { 16 | "output": "CHANGELOG.md", 17 | "template": "keepachangelog", 18 | "unreleased": true, 19 | "commitLimit": false 20 | }, 21 | "dependencies": { 22 | "lodash": "^4.17.19", 23 | "postcss-selector-parser": "^6.0.2" 24 | }, 25 | "publishConfig": { 26 | "registry": "https://registry.npmjs.org/" 27 | }, 28 | "devDependencies": { 29 | "auto-changelog": "^2.2.0", 30 | "github-release-from-changelog": "^2.1.1", 31 | "jest": "^26.1.0", 32 | "jest-matcher-css": "^1.1.0", 33 | "postcss": "^7.0.32", 34 | "release-it": "^13.6.5", 35 | "tailwindcss": "^1.5.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'es5', 3 | tabWidth: 2, 4 | semi: false, 5 | singleQuote: true, 6 | } 7 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const cssMatcher = require('jest-matcher-css') 3 | const postcss = require('postcss') 4 | const tailwindcss = require('tailwindcss') 5 | 6 | /** 7 | * generatePluginCss 8 | * Handles generating base tailwind css 9 | * @param {*} config 10 | * @param {object} pluginOptions are the options passed to the plugin 11 | * @return 12 | */ 13 | const generatePluginCss = (config, pluginOptions = {}) => { 14 | return postcss( 15 | tailwindcss( 16 | _.merge( 17 | { 18 | theme: { 19 | width: {}, 20 | height: {}, 21 | }, 22 | variants: [], 23 | corePlugins: ['width', 'height'], 24 | plugins: [require('./index.js')(pluginOptions)], 25 | }, 26 | config 27 | ) 28 | ) 29 | ) 30 | .process('@tailwind components; @tailwind utilities', { 31 | from: undefined, 32 | }) 33 | .then((result) => { 34 | // console.log('results', result.css) 35 | return result.css 36 | }) 37 | } 38 | 39 | /** 40 | * Base display classes from TailwindCSS 41 | * Note: I can't figure out how to get around these. If display 42 | * is not added above to corePlugins, nothing shows up 43 | */ 44 | const baseCss = ` 45 | ` 46 | 47 | expect.extend({ 48 | toMatchCss: cssMatcher, 49 | }) 50 | 51 | test('Nine hundred widths are generated by default', () => { 52 | return generatePluginCss(null, {}).then((css) => { 53 | expect(css).toMatch(/(w-900px)/) 54 | }) 55 | }) 56 | 57 | test('Nine hundred heights are generated by default', () => { 58 | return generatePluginCss(null, {}).then((css) => { 59 | expect(css).toMatch(/(h-900px)/) 60 | }) 61 | }) 62 | 63 | // Note: If the results contain a backslash, add another to escape it. 64 | test('A single width and height can be added', () => { 65 | return generatePluginCss( 66 | {}, 67 | { 68 | width: { 69 | total: 1, 70 | }, 71 | height: { 72 | total: 1, 73 | }, 74 | } 75 | ).then((css) => { 76 | expect(css).toMatchCss(` 77 | .w-0px { 78 | width: 0; 79 | } 80 | 81 | .w-1px { 82 | width: 1px; 83 | } 84 | 85 | .h-0px { 86 | height: 0; 87 | } 88 | 89 | .h-1px { 90 | height: 1px; 91 | } 92 | `) 93 | }) 94 | }) 95 | 96 | test('Multiple widths and heights can be added', () => { 97 | return generatePluginCss( 98 | {}, 99 | { 100 | width: { 101 | total: 10, 102 | }, 103 | height: { 104 | total: 10, 105 | }, 106 | } 107 | ).then((css) => { 108 | expect(css).toMatchCss(` 109 | .w-0px { 110 | width: 0; 111 | } 112 | 113 | .w-1px { 114 | width: 1px; 115 | } 116 | 117 | .w-2px { 118 | width: 2px; 119 | } 120 | 121 | .w-3px { 122 | width: 3px; 123 | } 124 | 125 | .w-4px { 126 | width: 4px; 127 | } 128 | 129 | .w-5px { 130 | width: 5px; 131 | } 132 | 133 | .w-6px { 134 | width: 6px; 135 | } 136 | 137 | .w-7px { 138 | width: 7px; 139 | } 140 | 141 | .w-8px { 142 | width: 8px; 143 | } 144 | 145 | .w-9px { 146 | width: 9px; 147 | } 148 | 149 | .w-10px { 150 | width: 10px; 151 | } 152 | 153 | .h-0px { 154 | height: 0; 155 | } 156 | 157 | .h-1px { 158 | height: 1px; 159 | } 160 | 161 | .h-2px { 162 | height: 2px; 163 | } 164 | 165 | .h-3px { 166 | height: 3px; 167 | } 168 | 169 | .h-4px { 170 | height: 4px; 171 | } 172 | 173 | .h-5px { 174 | height: 5px; 175 | } 176 | 177 | .h-6px { 178 | height: 6px; 179 | } 180 | 181 | .h-7px { 182 | height: 7px; 183 | } 184 | 185 | .h-8px { 186 | height: 8px; 187 | } 188 | 189 | .h-9px { 190 | height: 9px; 191 | } 192 | 193 | .h-10px { 194 | height: 10px; 195 | } 196 | `) 197 | }) 198 | }) 199 | --------------------------------------------------------------------------------