├── .editorconfig ├── .gitattributes ├── .gitignore ├── Readme.md ├── index.styl ├── lib ├── type-utils.js └── type-utils │ ├── config.styl │ ├── functions.styl │ └── index.styl ├── package.json └── test ├── cases ├── default.css ├── default.styl ├── ignore-base.css ├── ignore-base.styl ├── three-of-four.css └── three-of-four.styl └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | ; top-most EditorConfig file 2 | root = true 3 | 4 | ; Unix newlines, spaces and width of two by default 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | 16 | [*.styl] 17 | indent_style = tab 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Read about how to use .gitignore: http://h5bp.com/ae 2 | 3 | # Numerous always-ignore extensions 4 | *.diff 5 | *.err 6 | *.orig 7 | *.log 8 | *.rej 9 | *.swo 10 | *.swp 11 | *.vi 12 | *~ 13 | *.sass-cache 14 | 15 | # OS or Editor folders 16 | .DS_Store 17 | ._* 18 | Thumbs.db 19 | .cache 20 | .project 21 | .settings 22 | .tmproj 23 | nbproject 24 | *.sublime-project 25 | *.sublime-workspace 26 | 27 | # Dreamweaver added files 28 | _notes 29 | dwsync.xml 30 | 31 | # Komodo 32 | *.komodoproject 33 | .komodotools 34 | 35 | # Espresso 36 | *.esproj 37 | *.espressostorage 38 | 39 | # Rubinius 40 | *.rbc 41 | 42 | # Folders to ignore 43 | .hg 44 | .svn 45 | .CVS 46 | .idea 47 | 48 | # Project folders to ignore 49 | node_modules 50 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Stylus Type Utils 2 | 3 | Much needed Stylus typeography unit coersion and normalization. Provides several common unit conversion functions to convert between types effortlessly and in sync with the content font size. 4 | 5 | ## Installation 6 | 7 | npm install stylus-type-utils --save 8 | 9 | ### With Plugin Use 10 | 11 | stylus -u stylus-type-utils app.styl 12 | 13 | @import "type-utils"; 14 | 15 | ### With Direct Import 16 | 17 | @import "node_modules/stylus-type-utils"; 18 | 19 | ## API 20 | 21 | To use the `stylus-type-utils` library within your framework, use `@import` or use via the Stylus JS API. 22 | 23 | base-font-size = 100% // Change to adjust the conversion process 24 | support-for-ie = true // Set to `false` for no `px` output with `rem` 25 | 26 | px(unit, ignore-base-font-size) 27 | pt(unit, ignore-base-font-size) 28 | em(unit, ignore-base-font-size) 29 | rem(unit, ignore-base-font-size) 30 | percent(unit, ignore-base-font-size) 31 | 32 | When using the functions, omitting a unit type will assume the function unit type. E.g. `px(16) -> px(16px)`. 33 | 34 | The second parameter, `ignore-base-font-size`, allows the function to act as if the `base-font-size` was to set `100%`. 35 | 36 | ## Example Usage 37 | 38 | @import "node_modules/stylus-type-utils" 39 | 40 | base-font-size = 75% 41 | 42 | px(16) // 12px 43 | px(16, true) // 16px 44 | px(16px) // 12px 45 | px(1.2em) // 14.4px 46 | em(16px) // 0.75em 47 | 48 | rem(16px) // 12px, 0.75rem 49 | 50 | support-for-ie = false // No more px + rem output when using rem function 51 | 52 | rem(16px) // 0.75rem 53 | rem(16px, true) // 1rem 54 | 55 | base-font-size = 100% 56 | 57 | rem(16px) // 1rem 58 | 59 | 60 | ## License 61 | 62 | MIT 63 | -------------------------------------------------------------------------------- /index.styl: -------------------------------------------------------------------------------- 1 | @import "lib/type-utils" 2 | -------------------------------------------------------------------------------- /lib/type-utils.js: -------------------------------------------------------------------------------- 1 | var plugin = module.exports = function plugin () { 2 | 'use strict'; 3 | 4 | return function (style) { 5 | style.include(__dirname); 6 | }; 7 | }; 8 | 9 | plugin.path = __dirname; 10 | plugin.version = require(__dirname + '/../package.json').version; 11 | -------------------------------------------------------------------------------- /lib/type-utils/config.styl: -------------------------------------------------------------------------------- 1 | // Set the base font size of the HTML page 2 | base-font-size ?= 100% 3 | // Support for IE in the rem coersion 4 | support-for-ie ?= true 5 | -------------------------------------------------------------------------------- /lib/type-utils/functions.styl: -------------------------------------------------------------------------------- 1 | // Functions 2 | // -------------------------------------------------- 3 | 4 | replace(expr, str, val) 5 | expr = clone(expr) 6 | for e, i in expr 7 | if str == e 8 | expr[i] = val 9 | expr 10 | 11 | // Convert typographic units 12 | // 100% = 1em ~= 16px ~= 14pt 13 | // ---------------------------- 14 | px(amount, ignore-base = false) 15 | if unit(amount) == "%" 16 | amount = percent(base-font-size, ignore-base) / percent(base-font-size, true) * (amount / 100) * 16 17 | else if unit(amount) == "em" or unit(amount) == "rem" 18 | amount = em(base-font-size, ignore-base) / em(base-font-size, true) * amount * 16 19 | else if unit(amount) == "pt" 20 | amount = pt(base-font-size, ignore-base) / pt(base-font-size, true) * (amount / 14) * 16 21 | else if unit(amount) == "px" or unit(amount) == "" 22 | if (unit(base-font-size) != "px") && !ignore-base 23 | amount = px(base-font-size, true) / 16 * amount 24 | else if !ignore-base 25 | amount = base-font-size / 16 * amount 26 | 27 | unit(amount, "px") 28 | 29 | pt(amount, ignore-base = false) 30 | if unit(amount) == "%" 31 | amount = percent(base-font-size, ignore-base) / percent(base-font-size, true) * (amount / 100) * 14 32 | else if unit(amount) == "em" or unit(amount) == "rem" 33 | amount = em(base-font-size, ignore-base) / em(base-font-size, true) * amount * 14 34 | else if unit(amount) == "px" 35 | amount = px(base-font-size, ignore-base) / px(base-font-size, true) * (amount / 16) * 14 36 | else if unit(amount) == "pt" or unit(amount) == "" 37 | if (unit(base-font-size) != "pt") && !ignore-base 38 | amount = pt(base-font-size, true) / 14 * amount 39 | else if !ignore-base 40 | amount = base-font-size / 14 * amount 41 | 42 | unit(amount, "pt") 43 | 44 | em(amount, ignore-base = false) 45 | if unit(amount) == "%" 46 | amount = percent(base-font-size, ignore-base) / percent(base-font-size, true) * (amount / 100) 47 | else if unit(amount) == "px" 48 | amount = px(base-font-size, ignore-base) / px(base-font-size, true) * (amount / 16) 49 | else if unit(amount) == "pt" 50 | amount = pt(base-font-size, ignore-base) / pt(base-font-size, true) * (amount / 14) 51 | else if unit(amount) == "em" or unit(amount) == "rem" or unit(amount) == "" 52 | if (unit(base-font-size) != "em") && !ignore-base 53 | amount = em(base-font-size, true) * amount 54 | else if !ignore-base 55 | amount = base-font-size * amount 56 | 57 | unit(amount, "em") 58 | 59 | rem(amount, ignore-base = false) 60 | if support-for-ie 61 | add-property(current-property[0], replace(current-property[1], "__CALL__", px(em(amount, true), ignore-base))) 62 | unit(em(amount, ignore-base), "rem") 63 | 64 | percent(amount, ignore-base = false) 65 | if unit(amount) == "px" 66 | amount = px(base-font-size, ignore-base) / px(base-font-size, true) * (amount / 16) * 100 67 | else if unit(amount) == "em" or unit(amount) == "rem" 68 | amount = em(base-font-size, ignore-base) / em(base-font-size, true) * amount * 100 69 | else if unit(amount) == "pt" 70 | amount = pt(base-font-size, ignore-base) / pt(base-font-size, true) * (amount / 14) * 100 71 | else if unit(amount) == "%" or unit(amount) == "" 72 | if (unit(base-font-size) != "%") && !ignore-base 73 | amount = percent(base-font-size, true) / 100 * amount 74 | else if !ignore-base 75 | amount = base-font-size / 100 * amount 76 | 77 | unit(amount, "%") 78 | -------------------------------------------------------------------------------- /lib/type-utils/index.styl: -------------------------------------------------------------------------------- 1 | @import "config" 2 | @import "functions" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylus-type-utils", 3 | "version": "0.0.4", 4 | "description": "Stylus typography functions and type conversion", 5 | "main": "lib/type-utils.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/blakeembrey/stylus-type-utils.git" 12 | }, 13 | "keywords": [ 14 | "stylus", 15 | "typeograhy", 16 | "coercion", 17 | "rem", 18 | "em", 19 | "px", 20 | "pt", 21 | "percent" 22 | ], 23 | "homepage": "https://github.com/blakeembrey/stylus-type-utils", 24 | "author": "Blake Embrey", 25 | "license": "MIT", 26 | "readmeFilename": "Readme.md", 27 | "peerDependencies": { 28 | "stylus": "0.x" 29 | }, 30 | "devDependencies": { 31 | "stylus": "~0.32.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/cases/default.css: -------------------------------------------------------------------------------- 1 | .test-rem { 2 | default: 16px; 3 | default: 1rem; 4 | em-to-rem: 16px; 5 | em-to-rem: 1rem; 6 | px-to-rem: 16px; 7 | px-to-rem: 1rem; 8 | pt-to-rem: 16px; 9 | pt-to-rem: 1rem; 10 | percent-to-rem: 16px; 11 | percent-to-rem: 1rem; 12 | } 13 | .test-em { 14 | default: 1em; 15 | rem-to-em: 1em; 16 | px-to-em: 1em; 17 | pt-to-em: 1em; 18 | percent-to-em: 1em; 19 | } 20 | .test-px { 21 | default: 16px; 22 | rem-to-px: 16px; 23 | em-to-px: 16px; 24 | pt-to-px: 16px; 25 | percent-to-px: 16px; 26 | } 27 | .test-pt { 28 | default: 14pt; 29 | rem-to-pt: 14pt; 30 | em-to-pt: 14pt; 31 | px-to-pt: 14pt; 32 | percent-to-pt: 14pt; 33 | } 34 | .test-percent { 35 | default: 100%; 36 | rem-to-percent: 100%; 37 | em-to-percent: 100%; 38 | px-to-percent: 100%; 39 | pt-to-percent: 100%; 40 | } 41 | -------------------------------------------------------------------------------- /test/cases/default.styl: -------------------------------------------------------------------------------- 1 | .test-rem 2 | default: rem(1) 3 | em-to-rem: rem(1em) 4 | px-to-rem: rem(16px) 5 | pt-to-rem: rem(14pt) 6 | percent-to-rem: rem(100%) 7 | 8 | 9 | .test-em 10 | default: em(1) 11 | rem-to-em: em(1rem) 12 | px-to-em: em(16px) 13 | pt-to-em: em(14pt) 14 | percent-to-em: em(100%) 15 | 16 | 17 | .test-px 18 | default: px(16) 19 | rem-to-px: px(1rem) 20 | em-to-px: px(1em) 21 | pt-to-px: px(14pt) 22 | percent-to-px: px(100%) 23 | 24 | 25 | .test-pt 26 | default: pt(14) 27 | rem-to-pt: pt(1rem) 28 | em-to-pt: pt(1em) 29 | px-to-pt: pt(16px) 30 | percent-to-pt: pt(100%) 31 | 32 | 33 | .test-percent 34 | default: percent(100) 35 | rem-to-percent: percent(1rem) 36 | em-to-percent: percent(1em) 37 | px-to-percent: percent(16px) 38 | pt-to-percent: percent(14pt) 39 | -------------------------------------------------------------------------------- /test/cases/ignore-base.css: -------------------------------------------------------------------------------- 1 | .test-rem { 2 | default: 16px; 3 | default: 1rem; 4 | em-to-rem: 16px; 5 | em-to-rem: 1rem; 6 | px-to-rem: 16px; 7 | px-to-rem: 1rem; 8 | pt-to-rem: 16px; 9 | pt-to-rem: 1rem; 10 | percent-to-rem: 16px; 11 | percent-to-rem: 1rem; 12 | } 13 | .test-em { 14 | default: 1em; 15 | rem-to-em: 1em; 16 | px-to-em: 1em; 17 | pt-to-em: 1em; 18 | percent-to-em: 1em; 19 | } 20 | .test-px { 21 | default: 16px; 22 | rem-to-px: 16px; 23 | em-to-px: 16px; 24 | pt-to-px: 16px; 25 | percent-to-px: 16px; 26 | } 27 | .test-pt { 28 | default: 14pt; 29 | rem-to-pt: 14pt; 30 | em-to-pt: 14pt; 31 | px-to-pt: 14pt; 32 | percent-to-pt: 14pt; 33 | } 34 | .test-percent { 35 | default: 100%; 36 | rem-to-percent: 100%; 37 | em-to-percent: 100%; 38 | px-to-percent: 100%; 39 | pt-to-percent: 100%; 40 | } 41 | -------------------------------------------------------------------------------- /test/cases/ignore-base.styl: -------------------------------------------------------------------------------- 1 | base-font-size = 75% 2 | 3 | .test-rem 4 | default: rem(1, true) 5 | em-to-rem: rem(1em, true) 6 | px-to-rem: rem(16px, true) 7 | pt-to-rem: rem(14pt, true) 8 | percent-to-rem: rem(100%, true) 9 | 10 | 11 | .test-em 12 | default: em(1, true) 13 | rem-to-em: em(1rem, true) 14 | px-to-em: em(16px, true) 15 | pt-to-em: em(14pt, true) 16 | percent-to-em: em(100%, true) 17 | 18 | 19 | .test-px 20 | default: px(16, true) 21 | rem-to-px: px(1rem, true) 22 | em-to-px: px(1em, true) 23 | pt-to-px: px(14pt, true) 24 | percent-to-px: px(100%, true) 25 | 26 | 27 | .test-pt 28 | default: pt(14, true) 29 | rem-to-pt: pt(1rem, true) 30 | em-to-pt: pt(1em, true) 31 | px-to-pt: pt(16px, true) 32 | percent-to-pt: pt(100%, true) 33 | 34 | 35 | .test-percent 36 | default: percent(100, true) 37 | rem-to-percent: percent(1rem, true) 38 | em-to-percent: percent(1em, true) 39 | px-to-percent: percent(16px, true) 40 | pt-to-percent: percent(14pt, true) 41 | -------------------------------------------------------------------------------- /test/cases/three-of-four.css: -------------------------------------------------------------------------------- 1 | .test-rem { 2 | default: 12px; 3 | default: 0.75rem; 4 | em-to-rem: 12px; 5 | em-to-rem: 0.75rem; 6 | px-to-rem: 12px; 7 | px-to-rem: 0.75rem; 8 | pt-to-rem: 12px; 9 | pt-to-rem: 0.75rem; 10 | percent-to-rem: 12px; 11 | percent-to-rem: 0.75rem; 12 | } 13 | .test-em { 14 | default: 0.75em; 15 | rem-to-em: 0.75em; 16 | px-to-em: 0.75em; 17 | pt-to-em: 0.75em; 18 | percent-to-em: 0.75em; 19 | } 20 | .test-px { 21 | default: 12px; 22 | rem-to-px: 12px; 23 | em-to-px: 12px; 24 | pt-to-px: 12px; 25 | percent-to-px: 12px; 26 | } 27 | .test-pt { 28 | default: 10.5pt; 29 | rem-to-pt: 10.5pt; 30 | em-to-pt: 10.5pt; 31 | px-to-pt: 10.5pt; 32 | percent-to-pt: 10.5pt; 33 | } 34 | .test-percent { 35 | default: 75%; 36 | rem-to-percent: 75%; 37 | em-to-percent: 75%; 38 | px-to-percent: 75%; 39 | pt-to-percent: 75%; 40 | } 41 | -------------------------------------------------------------------------------- /test/cases/three-of-four.styl: -------------------------------------------------------------------------------- 1 | base-font-size = 75% 2 | 3 | .test-rem 4 | default: rem(1) 5 | em-to-rem: rem(1em) 6 | px-to-rem: rem(16px) 7 | pt-to-rem: rem(14pt) 8 | percent-to-rem: rem(100%) 9 | 10 | 11 | .test-em 12 | default: em(1) 13 | rem-to-em: em(1rem) 14 | px-to-em: em(16px) 15 | pt-to-em: em(14pt) 16 | percent-to-em: em(100%) 17 | 18 | 19 | .test-px 20 | default: px(16) 21 | rem-to-px: px(1rem) 22 | em-to-px: px(1em) 23 | pt-to-px: px(14pt) 24 | percent-to-px: px(100%) 25 | 26 | 27 | .test-pt 28 | default: pt(14) 29 | rem-to-pt: pt(1rem) 30 | em-to-pt: pt(1em) 31 | px-to-pt: pt(16px) 32 | percent-to-pt: pt(100%) 33 | 34 | 35 | .test-percent 36 | default: percent(100) 37 | rem-to-percent: percent(1rem) 38 | em-to-percent: percent(1em) 39 | px-to-percent: percent(16px) 40 | pt-to-percent: percent(14pt) 41 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*global describe,it*/ 2 | 'use strict'; 3 | 4 | // Stolen from https://github.com/visionmedia/nib/blob/master/test/runner.js 5 | var fs = require('fs'), 6 | stylus = require('stylus'), 7 | typeUtils = require('../'), 8 | assert = require('assert'); 9 | 10 | var cases = fs.readdirSync('test/cases').filter(function (file) { 11 | return ~file.indexOf('.styl'); 12 | }).map(function (file) { 13 | return file.replace('.styl', ''); 14 | }); 15 | 16 | describe('integration', function () { 17 | cases.forEach(function (test) { 18 | var name = test.replace(/[\-\.]/g, ' '); 19 | it(name, function () { 20 | var path = 'test/cases/' + test + '.styl', 21 | styl = fs.readFileSync(path, 'utf8').replace(/\r/g, ''), 22 | css = fs.readFileSync('test/cases/' + test + '.css', 'utf8').replace(/\r/g, '').trim(); 23 | 24 | var style = stylus(styl) 25 | .use(typeUtils()) 26 | .import('type-utils') 27 | .set('filename', path) 28 | .define('url', stylus.url()); 29 | 30 | if (~test.indexOf('compress')) { style.set('compress', true); } 31 | 32 | style.render(function (err, actual) { 33 | if (err) { throw err; } 34 | assert.equal(actual.trim(), css); 35 | }); 36 | }); 37 | }); 38 | }); 39 | --------------------------------------------------------------------------------