├── .compositor ├── .gitignore ├── .prettierrc ├── docs └── index.html ├── example ├── .compositor ├── app.pcss ├── compositor.config.js ├── fonts │ ├── inter │ │ ├── Inter-Bold.woff │ │ ├── Inter-Bold.woff2 │ │ ├── Inter-BoldItalic.woff │ │ ├── Inter-BoldItalic.woff2 │ │ ├── Inter-Italic.woff │ │ ├── Inter-Italic.woff2 │ │ ├── Inter-Regular.woff │ │ ├── Inter-Regular.woff2 │ │ ├── Inter-SemiBold.woff │ │ ├── Inter-SemiBold.woff2 │ │ ├── Inter-SemiBoldItalic.woff │ │ ├── Inter-SemiBoldItalic.woff2 │ │ └── Inter-italic.var.woff2 │ └── playfair │ │ ├── PlayfairDisplay-Black.ttf │ │ ├── PlayfairDisplay-BlackItalic.ttf │ │ ├── PlayfairDisplay-Bold.ttf │ │ ├── PlayfairDisplay-BoldItalic.ttf │ │ ├── PlayfairDisplay-ExtraBold.ttf │ │ ├── PlayfairDisplay-ExtraBoldItalic.ttf │ │ ├── PlayfairDisplay-Italic.ttf │ │ ├── PlayfairDisplay-Medium.ttf │ │ ├── PlayfairDisplay-MediumItalic.ttf │ │ ├── PlayfairDisplay-Regular.ttf │ │ ├── PlayfairDisplay-SemiBold.ttf │ │ └── PlayfairDisplay-SemiBoldItalic.ttf ├── index.html ├── package.json ├── postcss.config.js └── tailwind.config.js ├── jest.config.base.js ├── jest.config.js ├── jest.setup.js ├── lerna.json ├── licence.md ├── notes.md ├── package.json ├── plugin ├── images │ ├── baseline-type.gif │ ├── typeset-differences.gif │ └── vertical-metrics.png ├── jest.config.js ├── package.json ├── readme.md ├── rollup.config.js ├── src │ ├── __tests__ │ │ ├── __mocks__ │ │ │ └── styleMock.js │ │ ├── __snapshots__ │ │ │ ├── compositor.file.test.ts.snap │ │ │ └── plugin.test.ts.snap │ │ ├── compositor.file.test.ts │ │ ├── fixtures │ │ │ ├── compositor.config.js │ │ │ ├── inter │ │ │ │ └── Inter-Regular.woff │ │ │ ├── playfair │ │ │ │ ├── PlayfairDisplay-Black.ttf │ │ │ │ ├── PlayfairDisplay-BlackItalic.ttf │ │ │ │ ├── PlayfairDisplay-Bold.ttf │ │ │ │ ├── PlayfairDisplay-BoldItalic.ttf │ │ │ │ ├── PlayfairDisplay-ExtraBold.ttf │ │ │ │ ├── PlayfairDisplay-ExtraBoldItalic.ttf │ │ │ │ ├── PlayfairDisplay-Italic.ttf │ │ │ │ ├── PlayfairDisplay-Medium.ttf │ │ │ │ ├── PlayfairDisplay-MediumItalic.ttf │ │ │ │ ├── PlayfairDisplay-Regular.ttf │ │ │ │ ├── PlayfairDisplay-SemiBold.ttf │ │ │ │ └── PlayfairDisplay-SemiBoldItalic.ttf │ │ │ └── tailwind.config.js │ │ ├── plugin.test.ts │ │ └── transform.test.ts │ ├── create-background-styles.ts │ ├── create-matrix-styles.ts │ ├── create-measure-styles.ts │ ├── create-rhythm-styles.ts │ ├── create-text-styles.ts │ ├── default-config.ts │ ├── get-font-metrics.ts │ ├── index.ts │ ├── styles │ │ ├── index.ts │ │ ├── style-background.ts │ │ ├── style-font-family.ts │ │ ├── style-matrix.ts │ │ ├── style-measure.ts │ │ ├── style-owl.ts │ │ └── style-text.ts │ ├── tailwind-plugin-compositor.ts │ ├── theme-compositor.ts │ ├── types.ts │ └── utils │ │ ├── baseline-scale-to-px.ts │ │ ├── baseline-scale-to-rem.ts │ │ ├── get-rhythm.ts │ │ ├── get.ts │ │ ├── index.ts │ │ ├── is.ts │ │ ├── mem.ts │ │ ├── merge.ts │ │ ├── noop.ts │ │ ├── px-scale-to-rem.ts │ │ ├── px-to-rem.ts │ │ ├── scale-add-suffix.ts │ │ ├── strip-css.ts │ │ └── uuid.ts ├── tsconfig.json └── types.d.ts ├── readme.md ├── scripts └── rollup.base.js ├── tsconfig.json ├── tsconfig.settings.json ├── tslint.json └── yarn.lock /.compositor: -------------------------------------------------------------------------------- 1 | [{"familyName":"Inter","upm":2816,"xHeight":1536,"capHeight":2048,"lineGap":0,"ascent":2728,"descent":-680,"weight":400,"italic":false,"key":"sans-400"}] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dummy 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.pid.lock 14 | *.seed 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (http://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | **/node_modules 40 | 41 | # Typescript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # dev 63 | **/dev/ 64 | **/**/dev/ 65 | 66 | 67 | # dist 68 | **/dist/ 69 | **/**/dist/ 70 | 71 | # gatsby 72 | **/**/public 73 | **/**/.cache 74 | 75 | # Storybook 76 | storybook-static 77 | 78 | 79 | 80 | # Mac files 81 | .DS_Store 82 | 83 | # Cache files 84 | .cache 85 | **/**/.cache 86 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": true, 4 | "trailingComma": "es5", 5 | "tabWidth": 4, 6 | "useTabs": true, 7 | "singleQuote": true, 8 | "bracketSpacing": true, 9 | "arrowParens": "avoid" 10 | } 11 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/.compositor: -------------------------------------------------------------------------------- 1 | [{"key":"serif","familyName":"Playfair Display","fallback":"serif","upm":1000,"xHeight":514,"capHeight":708,"ascent":1082,"descent":-251,"lineGap":0,"weight":400,"italic":true},{"familyName":"Inter","upm":2816,"xHeight":1536,"capHeight":2048,"lineGap":0,"ascent":2728,"descent":-680,"weight":400,"italic":false,"key":"sans","fallback":"sans-serif"}] -------------------------------------------------------------------------------- /example/app.pcss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /example/compositor.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | // root font size 4 | const root = 16; 5 | 6 | // baseline grid row height in px 7 | const baseline = 8; 8 | 9 | // max leading count 10 | const leading = 4; 11 | 12 | const matrix = 12; 13 | 14 | // type scale in px 15 | const type = [ 16 | 12, 17 | 14, 18 | 16, 19 | 18, 20 | 20, 21 | 24, 22 | 28, 23 | 32, 24 | 36, 25 | 42, 26 | 48, 27 | 54, 28 | 60, 29 | 68, 30 | 76, 31 | 84, 32 | 92, 33 | ]; 34 | 35 | // rhythm scale in baseline units 36 | const rhythm = [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14]; 37 | rhythm.px = '1px'; 38 | rhythm.half = 0.5; 39 | 40 | // measure scale in characters unit 41 | const measure = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65]; 42 | measure.auto = 'auto'; 43 | 44 | // font config 45 | const fonts = [ 46 | { 47 | key: 'serif', 48 | familyName: 'Playfair Display', 49 | fallback: 'serif', 50 | upm: 1000, 51 | xHeight: 514, 52 | capHeight: 708, 53 | ascent: 1082, 54 | descent: -251, 55 | lineGap: 0, 56 | weight: 400, 57 | italic: true, 58 | }, 59 | { 60 | key: 'sans', 61 | fallback: 'sans-serif', 62 | file: path.resolve('./fonts/inter/Inter-Regular.woff2'), 63 | }, 64 | ]; 65 | 66 | module.exports = { 67 | root, 68 | baseline, 69 | leading, 70 | matrix, 71 | type, 72 | rhythm, 73 | measure, 74 | fonts, 75 | options: { 76 | useRem: true, 77 | snap: true, 78 | type: true, 79 | rhythm: true, 80 | measure: true, 81 | matrix: true, 82 | xray: true, 83 | }, 84 | }; 85 | -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-BoldItalic.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-BoldItalic.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Italic.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Italic.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-SemiBoldItalic.woff -------------------------------------------------------------------------------- /example/fonts/inter/Inter-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /example/fonts/inter/Inter-italic.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/inter/Inter-italic.var.woff2 -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-Black.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-BlackItalic.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-Bold.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-BoldItalic.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-ExtraBold.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-Italic.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-Medium.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-MediumItalic.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-Regular.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-SemiBold.ttf -------------------------------------------------------------------------------- /example/fonts/playfair/PlayfairDisplay-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/example/fonts/playfair/PlayfairDisplay-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tailwind Compositor 6 | 7 | 8 | 12 | 16 | 17 | 18 | 19 | 20 |
21 |
Tailwind
Compositor
22 |

23 | Amet et non nisi ex ex labore irure pariatur enim quis magna 24 | amet est esse. Dolore ad qui ea laboris labore non anim ad ipsum 25 | laborum est. 26 |

27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
37 |
40 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "description": "", 4 | "private": true, 5 | "author": "Apostolos Christodoulou (@a7sc11u)", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "@fullhuman/postcss-purgecss": "^2.2.0", 9 | "fontkit": "^1.8.1", 10 | "parcel": "^1.12.4", 11 | "postcss": "^7.0.32", 12 | "postcss-import": "^12.0.1", 13 | "postcss-preset-env": "^6.7.0", 14 | "stylelint": "^13.5.0", 15 | "stylelint-config-standard": "^20.0.0", 16 | "tailwind-compositor": "^1.0.3", 17 | "tailwindcss": "^1.5.2" 18 | }, 19 | "browserslist": "last 1 Chrome version", 20 | "scripts": { 21 | "develop": "rm -rf .cache && parcel index.html -d dev --target browser" 22 | }, 23 | "gitHead": "687d4c4559fc4813caff7eca184409c8993455d9" 24 | } 25 | -------------------------------------------------------------------------------- /example/postcss.config.js: -------------------------------------------------------------------------------- 1 | const tailwindcss = require('tailwindcss'); 2 | const { compositor } = require('tailwind-compositor'); 3 | const purgecss = require('@fullhuman/postcss-purgecss'); 4 | 5 | const compositorConfig = require('./compositor.config.js'); 6 | const tailwindConfig = require('./tailwind.config.js'); 7 | 8 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 9 | module.exports = { 10 | plugins: [ 11 | require('postcss-import')({ 12 | plugins: [require('stylelint')], 13 | }), 14 | tailwindcss(tailwindConfigComposed), 15 | ...(process.env.NODE_ENV === 'production' 16 | ? [ 17 | purgecss({ 18 | defaultExtractor: content => 19 | content.match(/[\w-/:]+(? 1%', 'last 2 versions', 'Firefox ESR'], 31 | }), 32 | ], 33 | }; 34 | -------------------------------------------------------------------------------- /example/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: { 3 | screens: { 4 | sm: '30rem', 5 | md: '42.5rem', 6 | lg: '80rem', 7 | xl: '105rem', 8 | }, 9 | colors: { 10 | transparent: 'transparent', 11 | current: 'currentColor', 12 | mono: [ 13 | '#000000', 14 | '#121212', 15 | '#303030', 16 | '#5E5E5E', 17 | '#878787', 18 | '#AAAAAA', 19 | '#C5C5C5', 20 | '#D9D9D9', 21 | '#E9E9E9', 22 | '#F4F4F4', 23 | '#FFFFFF', 24 | ], 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /jest.config.base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | roots: [''], 5 | transform: { 6 | '^.+\\.ts$': 'ts-jest', 7 | '^.+\\.tsx$': 'ts-jest', 8 | }, 9 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(ts?|tsx?)?$', 10 | moduleFileExtensions: ['js', 'ts', 'tsx', 'json', 'node', 'css', 'pcss'], 11 | coveragePathIgnorePatterns: ['(tests/.*.mock).(|ts?|tsx?)$'], 12 | verbose: true, 13 | testPathIgnorePatterns: ['/__snapshots__/', '/.cache/', '/lib/', '/dist/'], 14 | 15 | collectCoverage: false, 16 | collectCoverageFrom: ['**/*.{ts,tsx}', '!**/*.d.ts', '!/dist/'], 17 | snapshotSerializers: ['jest-emotion'], 18 | modulePathIgnorePatterns: [ 19 | '/__snapshots__/', 20 | 'dummy', 21 | 'scripts', 22 | 'docs', 23 | '__tests__/lib/', 24 | ], 25 | globals: { 26 | 'process.env.__DEV__': true, 27 | 'process.env.__PROD__': false, 28 | 'process.env.__BROWSER__': false, 29 | 'process.env.__SERVER__': false, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./jest.config.base.js'); 2 | 3 | module.exports = { 4 | ...base, 5 | setupFilesAfterEnv: ['./jest.setup.js'], 6 | projects: ['/plugin/jest.config.js'], 7 | }; 8 | -------------------------------------------------------------------------------- /jest.setup.js: -------------------------------------------------------------------------------- 1 | const cssMatcher = require('jest-matcher-css'); 2 | 3 | expect.extend({ 4 | toMatchCss: cssMatcher, 5 | }); 6 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.0.0", 3 | "packages": ["plugin", "example"], 4 | "version": "independent", 5 | "npmClient": "yarn", 6 | "licence": "MIT", 7 | "useWorkspaces": true 8 | } 9 | -------------------------------------------------------------------------------- /licence.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Apostolos Christodoulou 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 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | ``` 2 | module.exports = { 3 | options: { 4 | root: 16, 5 | baseline: 8, 6 | leading: 4, 7 | columns: 12, 8 | useRem: true, 9 | useGrid: true, 10 | }, 11 | scales: { 12 | type: true, 13 | measure: true, 14 | space: true, 15 | }, 16 | fonts: [], 17 | utilities: { 18 | type: ['responsive'], 19 | rhythm: ['responsive'], 20 | measure: ['responsive'], 21 | matrix: ['responsive'], 22 | xray: ['responsive'], 23 | }, 24 | }; 25 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind-plugin", 3 | "description": "", 4 | "private": true, 5 | "keywords": [ 6 | "tailwindcss", 7 | "typography", 8 | "baseline" 9 | ], 10 | "workspaces": [ 11 | "plugin", 12 | "example" 13 | ], 14 | "author": "Apostolos Christodoulou (@a7sc11u)", 15 | "main": "index.js", 16 | "license": "MIT", 17 | "scripts": { 18 | "postinstall": "lerna bootstrap", 19 | "develop": "npm-run-all -p plugin example", 20 | "plugin": "lerna exec --scope tailwind-compositor -- yarn develop", 21 | "build": "lerna exec --scope tailwind-compositor -- yarn build", 22 | "example": "lerna exec --scope example -- yarn run develop", 23 | "tdd": "jest --u --watch --onlyChanged --watchman --forceExit --detectOpenHandles --notify --notifyMode=failure", 24 | "release": "yarn test && yarn build && lerna publish --no-git-reset", 25 | "test": "jest --forceExit --detectOpenHandles --notify --notifyMode=failure" 26 | }, 27 | "devDependencies": { 28 | "@types/jest": "^25.2.3", 29 | "@types/node": "^12.7.5", 30 | "benchmark": "^2.1.4", 31 | "identity-obj-proxy": "^3.0.0", 32 | "jest": "^26.0.1", 33 | "jest-emotion": "^10.0.32", 34 | "jest-matcher-css": "^1.1.0", 35 | "jshint": "^2.10.2", 36 | "lerna": "^3.20.2", 37 | "npm-run-all": "^4.1.5", 38 | "prun": "^1.0.1", 39 | "typescript": "^3.9.3", 40 | "ts-jest": "^26.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /plugin/images/baseline-type.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/images/baseline-type.gif -------------------------------------------------------------------------------- /plugin/images/typeset-differences.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/images/typeset-differences.gif -------------------------------------------------------------------------------- /plugin/images/vertical-metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/images/vertical-metrics.png -------------------------------------------------------------------------------- /plugin/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../jest.config.base.js'); 2 | const pack = require('./package.json'); 3 | const packageName = pack.name; 4 | 5 | module.exports = { 6 | ...base, 7 | name: packageName, 8 | displayName: packageName, 9 | }; 10 | -------------------------------------------------------------------------------- /plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind-compositor", 3 | "version": "1.0.5-rc.0", 4 | "author": "Apostolos Christodoulou (@a7sc11u)", 5 | "license": "MIT", 6 | "homepage": "https://github.com/a7sc11u/tailwind-compositor#readme", 7 | "keywords": [ 8 | "tailwindcss", 9 | "typography", 10 | "baseline", 11 | "baseline-grid", 12 | "baseline-typography", 13 | "grid-system", 14 | "vertical-rhythm" 15 | ], 16 | "main": "dist/index.js", 17 | "module": "dist/index.es.js", 18 | "files": [ 19 | "dist" 20 | ], 21 | "types": "dist/index.d.ts", 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "scripts": { 26 | "develop": "rollup -cw", 27 | "build": "rollup -c" 28 | }, 29 | "peerDependencies": { 30 | "fontkit": "^1.8.1", 31 | "postcss": "^7.0.30", 32 | "tailwindcss": "^1.4.6" 33 | }, 34 | "dependencies": { 35 | "lodash.flattendeep": "^4.4.0" 36 | }, 37 | "devDependencies": { 38 | "csstype": "^2.6.9", 39 | "fontkit": "^1.8.1", 40 | "postcss": "^7.0.30", 41 | "rollup": "^1.19.4", 42 | "rollup-plugin-typescript2": "^0.24.0", 43 | "tailwindcss": "^1.4.6" 44 | }, 45 | "gitHead": "85ecdb3d33bb5ca7fbb1980e5670a8d2661f10fe" 46 | } 47 | -------------------------------------------------------------------------------- /plugin/readme.md: -------------------------------------------------------------------------------- 1 | # Tailwind Compositor 2 | 3 | Compositor is a system of constraints designed to produce aesthetically pleasing, typographic compositions, based on objective, constant dimensions of space. 4 | 5 | A baseline-grid typography system for [tailwindcss](https://tailwindcss.com/). 6 | 7 | Algorithm Demo: [Styled Baseline](https://styled-baseline.netlify.app/) 8 | 9 | --- 10 | 11 | ## Installation 12 | 13 | You will need fontkit, postcss and tailwindcss installed along with the plugin 14 | 15 | ``` 16 | npm install postcss fontkit tailwindcss tailwind-compositor 17 | ``` 18 | 19 | #### - postcss.config.js 20 | 21 | In your `postcss.config.js` you will need to import your standard `tailwind.config.js`, but also your `compositor.config.js`. 22 | 23 | The `{ compositor }` will receive both, merge with your tailwind config, and return a standard tailwind configuration. 24 | 25 | ``` 26 | const tailwindcss = require('tailwindcss'); 27 | const { compositor } = require('tailwind-compositor'); 28 | 29 | // import both configurations 30 | const compositorConfig = require('./compositor.config.js'); 31 | const tailwindConfig = require('./tailwind.config.js'); 32 | 33 | // compose config 34 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 35 | 36 | // use with tailwind 37 | module.exports = { 38 | plugins: [ 39 | tailwindcss(tailwindConfigComposed), 40 | ], 41 | }; 42 | ``` 43 | 44 | --- 45 | 46 | ## Configuration 47 | 48 | #### - compositor.config.js 49 | 50 | ``` 51 | const compositorConfig = { 52 | // root unit 53 | root: 16, 54 | 55 | // baseline grid height in px units 56 | baseline: 8, 57 | 58 | // maximum leading 59 | leading: 4, 60 | 61 | // matrix max columns 62 | matrix: 4, 63 | 64 | // type scale in px units 65 | type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56, 60, 72], 66 | 67 | // spacing scale in baseline units 68 | rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12], 69 | 70 | // line width in ch units 71 | measure: [10, 15, 20, 30, 35, 50, 55, 60, 65], 72 | 73 | // webfonts and vertical metrics 74 | fonts: [ 75 | { 76 | key: "sans-400", 77 | familyName: "Inter", 78 | fallback: "sans-serif", 79 | weight: 400, 80 | italic: false, 81 | upm: 2816, 82 | xHeight: 1536, 83 | capHeight: 2048, 84 | ascent: 2728, 85 | descent: -680 86 | }, 87 | { 88 | key: 'sans-600', 89 | familyName: "Inter", 90 | fallback: 'sans-serif', 91 | file: path.resolve('./fonts/inter/Inter-Semibold.woff2'), 92 | }, 93 | ], 94 | 95 | // compositor options 96 | options: { 97 | useRem: true, 98 | snap: true, 99 | type: true, 100 | rhythm: true, 101 | measure: true, 102 | matrix: true, 103 | xray: true, 104 | }, 105 | } 106 | ``` 107 | 108 | --- 109 | 110 | #### 1/9 - root: integer 111 | 112 | The root font size, in `px` units. 113 | 114 | --- 115 | 116 | #### 2/9 - baseline: integer 117 | 118 | The baseline grid row height, in `px` units. 119 | 120 | --- 121 | 122 | #### 3/9 - leading: integer 123 | 124 | The maximum leading value in baseline units. 125 | 126 | --- 127 | 128 | #### 4/9 - matrix: integer 129 | 130 | The maximum columns on the matrix utility 131 | 132 | --- 133 | 134 | #### 5/9 - type : array[integer] 135 | 136 | ``` 137 | type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56, 60, 72] 138 | ``` 139 | 140 | The system's typographic scale, in `px` units. 141 | 142 | --- 143 | 144 | #### 6/9 - rhythm : array[integer] 145 | 146 | ``` 147 | rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12] 148 | ``` 149 | 150 | The system's size and spacing scale, in `baseline` units, used for `rhythm`, `margin`, `padding`, `width/min/max`, `height/min/max` and `grid-gap` utilities 151 | 152 | --- 153 | 154 | #### 7/9 - measure : array[integer] 155 | 156 | ``` 157 | measure: [10, 15, 20, 30, 35, 50, 55, 60, 65] 158 | ``` 159 | 160 | Separate scale used for `measure` (line-width) utilities, configured in `ch` units. 161 | 162 | --- 163 | 164 | #### 8/9 - fonts : array[opentype] 165 | 166 | The font scale provides all the information needed to render text styles. Each entry describes a font/weight/style set, and only those that are part of the system will be enabled. 167 | 168 | The `file` property, is used to extract the vertical metrics dynamically from the font-file. If you want to configure the metrics manually, you can omit the `file` prop. 169 | 170 | The `key` property is used to name the utility classes. The configuration bellow will produce four font styles. The recommended convention is `${family}-${weight}${style}`. 171 | 172 | 1. `font-sans-400` : Inter Regular 173 | 2. `font-sans-400i` : Inter Regular Italic 174 | 3. `font-sans-600i` : Inter Semibold 175 | 4. `font-sans-600i` : Inter Semibold Italic 176 | 177 | ``` 178 | { 179 | key: "sans-400", 180 | familyName: "Inter", 181 | fallback: "sans-serif", 182 | weight: 400, 183 | italic: false, 184 | upm: 2816, 185 | xHeight: 1536, 186 | capHeight: 2048, 187 | lineGap: 0, 188 | ascent: 2728, 189 | descent: -680 190 | }, 191 | { 192 | key: 'sans-400i', 193 | familyName: "Inter", 194 | fallback: 'sans-serif', 195 | file: path.resolve('./fonts/inter/Inter-Italic.woff2'), 196 | }, 197 | { 198 | key: 'sans-600', 199 | familyName: "Inter", 200 | fallback: 'sans-serif', 201 | file: path.resolve('./fonts/inter/Inter-Semibold.woff2'), 202 | }, 203 | { 204 | key: 'sans-600i', 205 | familyName: "Inter", 206 | fallback: 'sans-serif', 207 | file: path.resolve('./fonts/inter/Inter-SemiboldItalic.woff2'), 208 | }, 209 | ``` 210 | 211 | --- 212 | 213 | #### 9/9 - Options : object 214 | 215 | Options properties, are used to enable/disable individual compositor utilities. 216 | 217 | If `useRem` is set to true, compositor will use the root unit value, to transform all spacing and font-size utilities, to relative units. Line-height will be transformed to unitless ratios. 218 | 219 | If `snap` is true, compositor will align each line text to the nearest baseline grid row, otherwise will trim the line-height above the capHeight and below the baseline, and apply a constant lineGap between lines of text. 220 | 221 | - `useRem: boolean` transform to relative units 222 | - `snap: boolean` Align text styles to a baseline grid 223 | `type: boolean` Enable typographic utilities 224 | - `rhythm: boolean` Enable rhythm utilities 225 | - `measure: boolean` Enable measure utilities 226 | - `matrix: boolean` Enable matrix utilities 227 | - `xray: boolean` Enable debug utilities 228 | 229 | ``` 230 | options: { 231 | useRem: true, 232 | snap: true, 233 | type: true, 234 | rhythm: true, 235 | measure: true, 236 | matrix: true, 237 | xray: true, 238 | } 239 | ``` 240 | 241 | --- 242 | 243 | ## Tailwind Utility Classes 244 | 245 | #### 1/7 - Typography 246 | 247 | ##### Font & Font Style 248 | 249 | - font: `font-{font-key}` 250 | 251 | ``` 252 | 253 | // fonts: [ 254 | // { key: "sans-400", ... }, 255 | // { key: 'sans-400i', ... }, 256 | // { key: 'sans-600', ... }, 257 | // { key: 'sans-600i', ... }, 258 | // ], 259 | 260 | // sans semibold italic 261 |

262 | 263 | // sans regular 264 |

265 | 266 | // sans regular italic 267 |

268 | ``` 269 | 270 | ##### Text Style 271 | 272 | - Text Style : `text-{type_scale_index}/{leading_baseline_units}` 273 | 274 | ``` 275 | 276 | // type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56] 277 | 278 | // sans semibold italic - 56px / leading 3 279 |

280 | 281 | // sans regular - 20px / leading 3 282 |

283 | 284 | // sans regular italic - 18px / leading 2 285 |

286 | ``` 287 | 288 | 289 | --- 290 | 291 | #### 2/7 - Line Width 292 | 293 | - `measure-{measure_scale_index}` 294 | 295 | ``` 296 | // measure: [10, 15, 20, 30, 35, 50, 55, 60, 65] 297 | 298 | // 10ch 299 |

Ad proident quis enim duis commodo.

300 | 301 | // 15ch 302 |

Ad proident quis enim duis commodo.

303 | 304 | // 20ch 305 |

Ad proident quis enim duis commodo.

306 | 307 | // 30ch 308 |

Ad proident quis enim duis commodo.

309 | ``` 310 | 311 | --- 312 | 313 | #### 3/7 - Spacing 314 | 315 | When the tailwind theme is composed, the rhythm scale is transformed to tailwindcss spacing scale and can be used for all spacing utilities, margin, padding and grid-gap. 316 | 317 | - Margin: `m-{rhythm_scale_index}` 318 | - Margin Left: `ml-{rhythm_scale_index}` 319 | - Padding: `p-{rhythm_scale_index}` 320 | - ...etc 321 | 322 | ``` 323 | 324 | // rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12] 325 | 326 |
327 |

328 | 329 |

330 |

331 | ``` 332 | 333 | --- 334 | 335 | #### 4/7 - Size 336 | 337 | Compositor also applies the spacing scale to tailwind sizing scales, width, min/max width and also height min/max. 338 | 339 | - Height: `h-{rhythm_scale_index}` 340 | - Min Height: `min-h-{rhythm_scale_index}` 341 | - Max Height: `max-h-{rhythm_scale_index}` 342 | - ...etc 343 | - 344 | 345 | ``` 346 |
347 |
349 | ``` 350 | 351 | --- 352 | 353 | #### 5/7 - Lobotomized Owls 354 | 355 | - Vertical rhythm (alias): `rhythm-{rhythm_scale_index}` 356 | - Vertical rhythm: `rhythm-y-{rhythm_scale_index}` 357 | - Horizontal Rhythm: `rhythm-x-{rhythm_scale_index}` 358 | 359 | ``` 360 | 361 |
362 |

363 |

364 | 365 | // render horizontally 366 |

367 |
370 |

371 | ``` 372 | 373 | --- 374 | 375 | #### 6/7 - Matrix Utils 376 | 377 | ##### Matrix 378 | - Matrix: `matrix-{columns_length}` 379 | - Matrix Gap: `matrix-gap-{rhythm_scale_index}` 380 | - Matrix Gap X: `matrix-gap-x-{rhythm_scale_index}` 381 | - Matrix Gap Y: `matrix-gap-y-{rhythm_scale_index}` 382 | 383 | ##### Cells 384 | By default every child of the matrix, will be placed in the next available column and will span for 1 column. In many cases you might not need any cell utilities or only the `cell-span-x` utility. 385 | 386 | - Cell Start X: `cell-start-x-{columns_index}` 387 | - Cell Span X: `cell-span-x-{columns_index}` 388 | 389 | --- 390 | 391 | #### 7/7 - Dev Utils 392 | 393 | - Background grid lines: `bg-baseline` 394 | 395 | ``` 396 |
397 | ``` 398 | -------------------------------------------------------------------------------- /plugin/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfig } from '../scripts/rollup.base'; 2 | import pkg from './package.json'; 3 | 4 | export default createRollupConfig(pkg); 5 | -------------------------------------------------------------------------------- /plugin/src/__tests__/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /plugin/src/__tests__/__snapshots__/compositor.file.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`transform with font files 1`] = ` 4 | Object { 5 | "corePlugins": false, 6 | "important": false, 7 | "plugins": Array [ 8 | [Function], 9 | ], 10 | "prefix": "", 11 | "purge": Array [], 12 | "separator": ":", 13 | "target": "relaxed", 14 | "theme": Object { 15 | "colors": Object { 16 | "black": "#000", 17 | "current": "currentColor", 18 | "transparent": "transparent", 19 | "white": "#fff", 20 | }, 21 | "compositor": Object { 22 | "baseline": 10, 23 | "fonts": Array [ 24 | Object { 25 | "ascent": 2728, 26 | "capHeight": 2048, 27 | "descent": -680, 28 | "familyName": "Inter", 29 | "italic": false, 30 | "key": "sans-400", 31 | "lineGap": 0, 32 | "upm": 2816, 33 | "weight": 400, 34 | "xHeight": 1536, 35 | }, 36 | ], 37 | "leading": 2, 38 | "matrix": 6, 39 | "measure": Object { 40 | "0": "10ch", 41 | "1": "20ch", 42 | }, 43 | "options": Object { 44 | "matrix": true, 45 | "measure": true, 46 | "rhythm": true, 47 | "snap": true, 48 | "type": true, 49 | "useRem": false, 50 | "xray": true, 51 | }, 52 | "rhythm": Array [ 53 | 0, 54 | 1, 55 | 2, 56 | ], 57 | "root": 10, 58 | "styles": Object { 59 | "ruler": Object { 60 | "color": "rgba(255, 0, 255, 0.3)", 61 | }, 62 | }, 63 | "type": Array [ 64 | 10, 65 | 20, 66 | ], 67 | }, 68 | "extend": Object { 69 | "height": Object { 70 | "0": "0px", 71 | "1": "10px", 72 | "2": "20px", 73 | }, 74 | "maxHeight": Object { 75 | "0": "0px", 76 | "1": "10px", 77 | "100": "100px", 78 | "2": "20px", 79 | }, 80 | "maxWidth": Object { 81 | "100": "100px", 82 | }, 83 | "minHeight": Object { 84 | "0": "0px", 85 | "1": "10px", 86 | "100": "100px", 87 | "2": "20px", 88 | }, 89 | "minWidth": Object { 90 | "100": "100px", 91 | }, 92 | }, 93 | "flex": Object { 94 | "auto": "1 1 auto", 95 | }, 96 | "fontFamily": Object { 97 | "sans": Array [ 98 | "system-ui", 99 | ], 100 | }, 101 | "fontSize": Array [ 102 | 10, 103 | 20, 104 | ], 105 | "fontWeight": Object { 106 | "bold": "700", 107 | "normal": "400", 108 | }, 109 | "letterSpacing": Object { 110 | "normal": "0", 111 | "wide": "0.025em", 112 | }, 113 | "lineHeight": Object { 114 | "none": "1", 115 | "normal": "1.5", 116 | }, 117 | "screens": Object { 118 | "sm": "640px", 119 | }, 120 | "spacing": Object { 121 | "0": "0px", 122 | "1": "10px", 123 | "2": "20px", 124 | }, 125 | }, 126 | "variants": Object { 127 | "accessibility": Array [], 128 | "alignContent": Array [], 129 | "alignItems": Array [], 130 | "alignSelf": Array [], 131 | "appearance": Array [], 132 | "backgroundAttachment": Array [], 133 | "backgroundColor": Array [], 134 | "backgroundOpacity": Array [], 135 | "backgroundPosition": Array [], 136 | "backgroundRepeat": Array [], 137 | "backgroundSize": Array [], 138 | "borderCollapse": Array [], 139 | "borderColor": Array [], 140 | "borderOpacity": Array [], 141 | "borderRadius": Array [], 142 | "borderStyle": Array [], 143 | "borderWidth": Array [], 144 | "boxShadow": Array [], 145 | "boxSizing": Array [], 146 | "clear": Array [], 147 | "cursor": Array [], 148 | "display": Array [], 149 | "divideColor": Array [], 150 | "divideOpacity": Array [], 151 | "divideWidth": Array [], 152 | "fill": Array [], 153 | "flex": Array [], 154 | "flexDirection": Array [], 155 | "flexGrow": Array [], 156 | "flexShrink": Array [], 157 | "flexWrap": Array [], 158 | "float": Array [], 159 | "fontFamily": Array [], 160 | "fontSize": Array [], 161 | "fontSmoothing": Array [], 162 | "fontStyle": Array [], 163 | "fontWeight": Array [], 164 | "gap": Array [], 165 | "gridAutoFlow": Array [], 166 | "gridColumn": Array [], 167 | "gridColumnEnd": Array [], 168 | "gridColumnStart": Array [], 169 | "gridRow": Array [], 170 | "gridRowEnd": Array [], 171 | "gridRowStart": Array [], 172 | "gridTemplateColumns": Array [], 173 | "gridTemplateRows": Array [], 174 | "height": Array [], 175 | "inset": Array [], 176 | "justifyContent": Array [], 177 | "letterSpacing": Array [], 178 | "lineHeight": Array [], 179 | "listStylePosition": Array [], 180 | "listStyleType": Array [], 181 | "margin": Array [], 182 | "maxHeight": Array [], 183 | "maxWidth": Array [], 184 | "minHeight": Array [], 185 | "minWidth": Array [], 186 | "objectFit": Array [], 187 | "objectPosition": Array [], 188 | "opacity": Array [], 189 | "order": Array [], 190 | "outline": Array [], 191 | "overflow": Array [], 192 | "padding": Array [], 193 | "placeholderColor": Array [], 194 | "placeholderOpacity": Array [], 195 | "pointerEvents": Array [], 196 | "position": Array [], 197 | "resize": Array [], 198 | "rotate": Array [], 199 | "scale": Array [], 200 | "skew": Array [], 201 | "space": Array [], 202 | "stroke": Array [], 203 | "strokeWidth": Array [], 204 | "tableLayout": Array [], 205 | "textAlign": Array [], 206 | "textColor": Array [], 207 | "textDecoration": Array [], 208 | "textOpacity": Array [], 209 | "textTransform": Array [], 210 | "transform": Array [], 211 | "transformOrigin": Array [], 212 | "transitionDelay": Array [], 213 | "transitionDuration": Array [], 214 | "transitionProperty": Array [], 215 | "transitionTimingFunction": Array [], 216 | "translate": Array [], 217 | "userSelect": Array [], 218 | "verticalAlign": Array [], 219 | "visibility": Array [], 220 | "whitespace": Array [], 221 | "width": Array [], 222 | "wordBreak": Array [], 223 | "zIndex": Array [], 224 | }, 225 | } 226 | `; 227 | -------------------------------------------------------------------------------- /plugin/src/__tests__/__snapshots__/plugin.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`baseline styles 1`] = ` 4 | ".font-sans-400 { 5 | font-family: \\"IBM Plex Sans\\", sans-serif; 6 | font-weight: 400; 7 | font-style: normal; 8 | display: block; 9 | } 10 | 11 | .font-sans-400::before, .font-sans-400::after { 12 | content: ''; 13 | display: block; 14 | height: 0; 15 | } 16 | 17 | .font-sans-400.text-0\\\\/0 { 18 | font-size: 10px; 19 | line-height: 10px; 20 | padding-top: 3.42px; 21 | padding-bottom: 0.4px; 22 | } 23 | 24 | .font-sans-400.text-0\\\\/0::before { 25 | margin-top: -2.17px; 26 | } 27 | 28 | .font-sans-400.text-0\\\\/0::after { 29 | margin-bottom: -1.65px; 30 | } 31 | 32 | .font-sans-400.text-0\\\\/1 { 33 | font-size: 10px; 34 | line-height: 20px; 35 | padding-top: 3.4199999999999995px; 36 | padding-bottom: 0.4px; 37 | } 38 | 39 | .font-sans-400.text-0\\\\/1::before { 40 | margin-top: -7.17px; 41 | } 42 | 43 | .font-sans-400.text-0\\\\/1::after { 44 | margin-bottom: -6.65px; 45 | } 46 | 47 | .font-sans-400.text-0\\\\/2 { 48 | font-size: 10px; 49 | line-height: 30px; 50 | padding-top: 3.4199999999999995px; 51 | padding-bottom: 0.4px; 52 | } 53 | 54 | .font-sans-400.text-0\\\\/2::before { 55 | margin-top: -12.17px; 56 | } 57 | 58 | .font-sans-400.text-0\\\\/2::after { 59 | margin-bottom: -11.65px; 60 | } 61 | 62 | .font-sans-400.text-1\\\\/0 { 63 | font-size: 20px; 64 | line-height: 10px; 65 | padding-top: -3.56px; 66 | padding-bottom: 0.4px; 67 | } 68 | 69 | .font-sans-400.text-1\\\\/0::before { 70 | margin-top: 1.06px; 71 | } 72 | 73 | .font-sans-400.text-1\\\\/0::after { 74 | margin-bottom: 2.1px; 75 | } 76 | 77 | .font-sans-400.text-1\\\\/1 { 78 | font-size: 20px; 79 | line-height: 20px; 80 | padding-top: 6.44px; 81 | padding-bottom: 0.4px; 82 | } 83 | 84 | .font-sans-400.text-1\\\\/1::before { 85 | margin-top: -3.94px; 86 | } 87 | 88 | .font-sans-400.text-1\\\\/1::after { 89 | margin-bottom: -2.9px; 90 | } 91 | 92 | .font-sans-400.text-1\\\\/2 { 93 | font-size: 20px; 94 | line-height: 30px; 95 | padding-top: 6.4399999999999995px; 96 | padding-bottom: 0.4px; 97 | } 98 | 99 | .font-sans-400.text-1\\\\/2::before { 100 | margin-top: -8.94px; 101 | } 102 | 103 | .font-sans-400.text-1\\\\/2::after { 104 | margin-bottom: -7.9px; 105 | } 106 | 107 | @media (min-width: 640px) { 108 | .font-sans-400.sm\\\\:text-0\\\\/0 { 109 | font-size: 10px; 110 | line-height: 10px; 111 | padding-top: 3.42px; 112 | padding-bottom: 0.4px; 113 | } 114 | 115 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 116 | margin-top: -2.17px; 117 | } 118 | 119 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 120 | margin-bottom: -1.65px; 121 | } 122 | 123 | .font-sans-400.sm\\\\:text-0\\\\/1 { 124 | font-size: 10px; 125 | line-height: 20px; 126 | padding-top: 3.4199999999999995px; 127 | padding-bottom: 0.4px; 128 | } 129 | 130 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 131 | margin-top: -7.17px; 132 | } 133 | 134 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 135 | margin-bottom: -6.65px; 136 | } 137 | 138 | .font-sans-400.sm\\\\:text-0\\\\/2 { 139 | font-size: 10px; 140 | line-height: 30px; 141 | padding-top: 3.4199999999999995px; 142 | padding-bottom: 0.4px; 143 | } 144 | 145 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 146 | margin-top: -12.17px; 147 | } 148 | 149 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 150 | margin-bottom: -11.65px; 151 | } 152 | 153 | .font-sans-400.sm\\\\:text-1\\\\/0 { 154 | font-size: 20px; 155 | line-height: 10px; 156 | padding-top: -3.56px; 157 | padding-bottom: 0.4px; 158 | } 159 | 160 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 161 | margin-top: 1.06px; 162 | } 163 | 164 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 165 | margin-bottom: 2.1px; 166 | } 167 | 168 | .font-sans-400.sm\\\\:text-1\\\\/1 { 169 | font-size: 20px; 170 | line-height: 20px; 171 | padding-top: 6.44px; 172 | padding-bottom: 0.4px; 173 | } 174 | 175 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 176 | margin-top: -3.94px; 177 | } 178 | 179 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 180 | margin-bottom: -2.9px; 181 | } 182 | 183 | .font-sans-400.sm\\\\:text-1\\\\/2 { 184 | font-size: 20px; 185 | line-height: 30px; 186 | padding-top: 6.4399999999999995px; 187 | padding-bottom: 0.4px; 188 | } 189 | 190 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 191 | margin-top: -8.94px; 192 | } 193 | 194 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 195 | margin-bottom: -7.9px; 196 | } 197 | }" 198 | `; 199 | 200 | exports[`capheight styles 1`] = ` 201 | ".font-sans-400 { 202 | font-family: \\"IBM Plex Sans\\", sans-serif; 203 | font-weight: 400; 204 | font-style: normal; 205 | display: block; 206 | } 207 | 208 | .font-sans-400::before, .font-sans-400::after { 209 | content: ''; 210 | display: block; 211 | height: 0; 212 | } 213 | 214 | .font-sans-400.text-0\\\\/0 { 215 | font-size: 10px; 216 | line-height: 6.9799999999999995px; 217 | padding-top: 0.4px; 218 | padding-bottom: 0.4px; 219 | } 220 | 221 | .font-sans-400.text-0\\\\/0::before { 222 | margin-top: -0.6599999999999998px; 223 | } 224 | 225 | .font-sans-400.text-0\\\\/0::after { 226 | margin-bottom: -0.1399999999999998px; 227 | } 228 | 229 | .font-sans-400.text-0\\\\/1 { 230 | font-size: 10px; 231 | line-height: 16.98px; 232 | padding-top: 0.4px; 233 | padding-bottom: 0.4px; 234 | } 235 | 236 | .font-sans-400.text-0\\\\/1::before { 237 | margin-top: -5.66px; 238 | } 239 | 240 | .font-sans-400.text-0\\\\/1::after { 241 | margin-bottom: -5.140000000000001px; 242 | } 243 | 244 | .font-sans-400.text-0\\\\/2 { 245 | font-size: 10px; 246 | line-height: 26.98px; 247 | padding-top: 0.4px; 248 | padding-bottom: 0.4px; 249 | } 250 | 251 | .font-sans-400.text-0\\\\/2::before { 252 | margin-top: -10.66px; 253 | } 254 | 255 | .font-sans-400.text-0\\\\/2::after { 256 | margin-bottom: -10.14px; 257 | } 258 | 259 | .font-sans-400.text-1\\\\/0 { 260 | font-size: 20px; 261 | line-height: 13.959999999999999px; 262 | padding-top: 0.4px; 263 | padding-bottom: 0.4px; 264 | } 265 | 266 | .font-sans-400.text-1\\\\/0::before { 267 | margin-top: -0.9199999999999996px; 268 | } 269 | 270 | .font-sans-400.text-1\\\\/0::after { 271 | margin-bottom: 0.12000000000000044px; 272 | } 273 | 274 | .font-sans-400.text-1\\\\/1 { 275 | font-size: 20px; 276 | line-height: 23.96px; 277 | padding-top: 0.4px; 278 | padding-bottom: 0.4px; 279 | } 280 | 281 | .font-sans-400.text-1\\\\/1::before { 282 | margin-top: -5.920000000000001px; 283 | } 284 | 285 | .font-sans-400.text-1\\\\/1::after { 286 | margin-bottom: -4.880000000000001px; 287 | } 288 | 289 | .font-sans-400.text-1\\\\/2 { 290 | font-size: 20px; 291 | line-height: 33.96px; 292 | padding-top: 0.4px; 293 | padding-bottom: 0.4px; 294 | } 295 | 296 | .font-sans-400.text-1\\\\/2::before { 297 | margin-top: -10.92px; 298 | } 299 | 300 | .font-sans-400.text-1\\\\/2::after { 301 | margin-bottom: -9.88px; 302 | } 303 | 304 | @media (min-width: 640px) { 305 | .font-sans-400.sm\\\\:text-0\\\\/0 { 306 | font-size: 10px; 307 | line-height: 6.9799999999999995px; 308 | padding-top: 0.4px; 309 | padding-bottom: 0.4px; 310 | } 311 | 312 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 313 | margin-top: -0.6599999999999998px; 314 | } 315 | 316 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 317 | margin-bottom: -0.1399999999999998px; 318 | } 319 | 320 | .font-sans-400.sm\\\\:text-0\\\\/1 { 321 | font-size: 10px; 322 | line-height: 16.98px; 323 | padding-top: 0.4px; 324 | padding-bottom: 0.4px; 325 | } 326 | 327 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 328 | margin-top: -5.66px; 329 | } 330 | 331 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 332 | margin-bottom: -5.140000000000001px; 333 | } 334 | 335 | .font-sans-400.sm\\\\:text-0\\\\/2 { 336 | font-size: 10px; 337 | line-height: 26.98px; 338 | padding-top: 0.4px; 339 | padding-bottom: 0.4px; 340 | } 341 | 342 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 343 | margin-top: -10.66px; 344 | } 345 | 346 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 347 | margin-bottom: -10.14px; 348 | } 349 | 350 | .font-sans-400.sm\\\\:text-1\\\\/0 { 351 | font-size: 20px; 352 | line-height: 13.959999999999999px; 353 | padding-top: 0.4px; 354 | padding-bottom: 0.4px; 355 | } 356 | 357 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 358 | margin-top: -0.9199999999999996px; 359 | } 360 | 361 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 362 | margin-bottom: 0.12000000000000044px; 363 | } 364 | 365 | .font-sans-400.sm\\\\:text-1\\\\/1 { 366 | font-size: 20px; 367 | line-height: 23.96px; 368 | padding-top: 0.4px; 369 | padding-bottom: 0.4px; 370 | } 371 | 372 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 373 | margin-top: -5.920000000000001px; 374 | } 375 | 376 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 377 | margin-bottom: -4.880000000000001px; 378 | } 379 | 380 | .font-sans-400.sm\\\\:text-1\\\\/2 { 381 | font-size: 20px; 382 | line-height: 33.96px; 383 | padding-top: 0.4px; 384 | padding-bottom: 0.4px; 385 | } 386 | 387 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 388 | margin-top: -10.92px; 389 | } 390 | 391 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 392 | margin-bottom: -9.88px; 393 | } 394 | }" 395 | `; 396 | 397 | exports[`matrix styles 1`] = ` 398 | ".font-sans-400 { 399 | font-family: \\"IBM Plex Sans\\", sans-serif; 400 | font-weight: 400; 401 | font-style: normal; 402 | display: block; 403 | } 404 | 405 | .font-sans-400::before, .font-sans-400::after { 406 | content: ''; 407 | display: block; 408 | height: 0; 409 | } 410 | 411 | .font-sans-400.text-0\\\\/0 { 412 | font-size: 10px; 413 | line-height: 6.9799999999999995px; 414 | padding-top: 0.4px; 415 | padding-bottom: 0.4px; 416 | } 417 | 418 | .font-sans-400.text-0\\\\/0::before { 419 | margin-top: -0.6599999999999998px; 420 | } 421 | 422 | .font-sans-400.text-0\\\\/0::after { 423 | margin-bottom: -0.1399999999999998px; 424 | } 425 | 426 | .font-sans-400.text-0\\\\/1 { 427 | font-size: 10px; 428 | line-height: 16.98px; 429 | padding-top: 0.4px; 430 | padding-bottom: 0.4px; 431 | } 432 | 433 | .font-sans-400.text-0\\\\/1::before { 434 | margin-top: -5.66px; 435 | } 436 | 437 | .font-sans-400.text-0\\\\/1::after { 438 | margin-bottom: -5.140000000000001px; 439 | } 440 | 441 | .font-sans-400.text-0\\\\/2 { 442 | font-size: 10px; 443 | line-height: 26.98px; 444 | padding-top: 0.4px; 445 | padding-bottom: 0.4px; 446 | } 447 | 448 | .font-sans-400.text-0\\\\/2::before { 449 | margin-top: -10.66px; 450 | } 451 | 452 | .font-sans-400.text-0\\\\/2::after { 453 | margin-bottom: -10.14px; 454 | } 455 | 456 | .font-sans-400.text-1\\\\/0 { 457 | font-size: 20px; 458 | line-height: 13.959999999999999px; 459 | padding-top: 0.4px; 460 | padding-bottom: 0.4px; 461 | } 462 | 463 | .font-sans-400.text-1\\\\/0::before { 464 | margin-top: -0.9199999999999996px; 465 | } 466 | 467 | .font-sans-400.text-1\\\\/0::after { 468 | margin-bottom: 0.12000000000000044px; 469 | } 470 | 471 | .font-sans-400.text-1\\\\/1 { 472 | font-size: 20px; 473 | line-height: 23.96px; 474 | padding-top: 0.4px; 475 | padding-bottom: 0.4px; 476 | } 477 | 478 | .font-sans-400.text-1\\\\/1::before { 479 | margin-top: -5.920000000000001px; 480 | } 481 | 482 | .font-sans-400.text-1\\\\/1::after { 483 | margin-bottom: -4.880000000000001px; 484 | } 485 | 486 | .font-sans-400.text-1\\\\/2 { 487 | font-size: 20px; 488 | line-height: 33.96px; 489 | padding-top: 0.4px; 490 | padding-bottom: 0.4px; 491 | } 492 | 493 | .font-sans-400.text-1\\\\/2::before { 494 | margin-top: -10.92px; 495 | } 496 | 497 | .font-sans-400.text-1\\\\/2::after { 498 | margin-bottom: -9.88px; 499 | } 500 | 501 | .matrix-0 { 502 | display: grid; 503 | grid-template-columns: repeat(1, minmax(auto,1fr)); 504 | } 505 | 506 | .matrix-1 { 507 | display: grid; 508 | grid-template-columns: repeat(1, minmax(auto,1fr)); 509 | } 510 | 511 | .matrix-2 { 512 | display: grid; 513 | grid-template-columns: repeat(2, minmax(auto,1fr)); 514 | } 515 | 516 | .matrix-3 { 517 | display: grid; 518 | grid-template-columns: repeat(3, minmax(auto,1fr)); 519 | } 520 | 521 | .matrix-4 { 522 | display: grid; 523 | grid-template-columns: repeat(4, minmax(auto,1fr)); 524 | } 525 | 526 | .matrix-5 { 527 | display: grid; 528 | grid-template-columns: repeat(5, minmax(auto,1fr)); 529 | } 530 | 531 | .matrix-6 { 532 | display: grid; 533 | grid-template-columns: repeat(6, minmax(auto,1fr)); 534 | } 535 | 536 | .matrix-row-h-0 { 537 | grid-auto-rows: minmax(0px, auto); 538 | } 539 | 540 | .matrix-gap-0 { 541 | grid-row-gap: 0px; 542 | grid-column-gap: 0px; 543 | } 544 | 545 | .matrix-gap-x-0 { 546 | grid-column-gap: 0px; 547 | } 548 | 549 | .matrix-gap-y-0 { 550 | grid-row-gap: 0px; 551 | } 552 | 553 | .matrix-row-h-1 { 554 | grid-auto-rows: minmax(10px, auto); 555 | } 556 | 557 | .matrix-gap-1 { 558 | grid-row-gap: 10px; 559 | grid-column-gap: 10px; 560 | } 561 | 562 | .matrix-gap-x-1 { 563 | grid-column-gap: 10px; 564 | } 565 | 566 | .matrix-gap-y-1 { 567 | grid-row-gap: 10px; 568 | } 569 | 570 | .matrix-row-h-2 { 571 | grid-auto-rows: minmax(20px, auto); 572 | } 573 | 574 | .matrix-gap-2 { 575 | grid-row-gap: 20px; 576 | grid-column-gap: 20px; 577 | } 578 | 579 | .matrix-gap-x-2 { 580 | grid-column-gap: 20px; 581 | } 582 | 583 | .matrix-gap-y-2 { 584 | grid-row-gap: 20px; 585 | } 586 | 587 | .cell-start-x-1 { 588 | grid-column-start: 1 !important; 589 | } 590 | 591 | .cell-span-x-1 { 592 | grid-column: auto / span 1; 593 | } 594 | 595 | .cell-start-y-1 { 596 | grid-row-start: 1 !important; 597 | } 598 | 599 | .cell-span-y-1 { 600 | grid-row: auto / span 1; 601 | } 602 | 603 | .cell-start-x-1 { 604 | grid-column-start: 1 !important; 605 | } 606 | 607 | .cell-span-x-1 { 608 | grid-column: auto / span 1; 609 | } 610 | 611 | .cell-start-y-1 { 612 | grid-row-start: 1 !important; 613 | } 614 | 615 | .cell-span-y-1 { 616 | grid-row: auto / span 1; 617 | } 618 | 619 | .cell-start-x-2 { 620 | grid-column-start: 2 !important; 621 | } 622 | 623 | .cell-span-x-2 { 624 | grid-column: auto / span 2; 625 | } 626 | 627 | .cell-start-y-2 { 628 | grid-row-start: 2 !important; 629 | } 630 | 631 | .cell-span-y-2 { 632 | grid-row: auto / span 2; 633 | } 634 | 635 | .cell-start-x-3 { 636 | grid-column-start: 3 !important; 637 | } 638 | 639 | .cell-span-x-3 { 640 | grid-column: auto / span 3; 641 | } 642 | 643 | .cell-start-y-3 { 644 | grid-row-start: 3 !important; 645 | } 646 | 647 | .cell-span-y-3 { 648 | grid-row: auto / span 3; 649 | } 650 | 651 | .cell-start-x-4 { 652 | grid-column-start: 4 !important; 653 | } 654 | 655 | .cell-span-x-4 { 656 | grid-column: auto / span 4; 657 | } 658 | 659 | .cell-start-y-4 { 660 | grid-row-start: 4 !important; 661 | } 662 | 663 | .cell-span-y-4 { 664 | grid-row: auto / span 4; 665 | } 666 | 667 | .cell-start-x-5 { 668 | grid-column-start: 5 !important; 669 | } 670 | 671 | .cell-span-x-5 { 672 | grid-column: auto / span 5; 673 | } 674 | 675 | .cell-start-y-5 { 676 | grid-row-start: 5 !important; 677 | } 678 | 679 | .cell-span-y-5 { 680 | grid-row: auto / span 5; 681 | } 682 | 683 | .cell-start-x-6 { 684 | grid-column-start: 6 !important; 685 | } 686 | 687 | .cell-span-x-6 { 688 | grid-column: auto / span 6; 689 | } 690 | 691 | .cell-start-y-6 { 692 | grid-row-start: 6 !important; 693 | } 694 | 695 | .cell-span-y-6 { 696 | grid-row: auto / span 6; 697 | } 698 | 699 | @media (min-width: 640px) { 700 | .font-sans-400.sm\\\\:text-0\\\\/0 { 701 | font-size: 10px; 702 | line-height: 6.9799999999999995px; 703 | padding-top: 0.4px; 704 | padding-bottom: 0.4px; 705 | } 706 | 707 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 708 | margin-top: -0.6599999999999998px; 709 | } 710 | 711 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 712 | margin-bottom: -0.1399999999999998px; 713 | } 714 | 715 | .font-sans-400.sm\\\\:text-0\\\\/1 { 716 | font-size: 10px; 717 | line-height: 16.98px; 718 | padding-top: 0.4px; 719 | padding-bottom: 0.4px; 720 | } 721 | 722 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 723 | margin-top: -5.66px; 724 | } 725 | 726 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 727 | margin-bottom: -5.140000000000001px; 728 | } 729 | 730 | .font-sans-400.sm\\\\:text-0\\\\/2 { 731 | font-size: 10px; 732 | line-height: 26.98px; 733 | padding-top: 0.4px; 734 | padding-bottom: 0.4px; 735 | } 736 | 737 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 738 | margin-top: -10.66px; 739 | } 740 | 741 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 742 | margin-bottom: -10.14px; 743 | } 744 | 745 | .font-sans-400.sm\\\\:text-1\\\\/0 { 746 | font-size: 20px; 747 | line-height: 13.959999999999999px; 748 | padding-top: 0.4px; 749 | padding-bottom: 0.4px; 750 | } 751 | 752 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 753 | margin-top: -0.9199999999999996px; 754 | } 755 | 756 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 757 | margin-bottom: 0.12000000000000044px; 758 | } 759 | 760 | .font-sans-400.sm\\\\:text-1\\\\/1 { 761 | font-size: 20px; 762 | line-height: 23.96px; 763 | padding-top: 0.4px; 764 | padding-bottom: 0.4px; 765 | } 766 | 767 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 768 | margin-top: -5.920000000000001px; 769 | } 770 | 771 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 772 | margin-bottom: -4.880000000000001px; 773 | } 774 | 775 | .font-sans-400.sm\\\\:text-1\\\\/2 { 776 | font-size: 20px; 777 | line-height: 33.96px; 778 | padding-top: 0.4px; 779 | padding-bottom: 0.4px; 780 | } 781 | 782 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 783 | margin-top: -10.92px; 784 | } 785 | 786 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 787 | margin-bottom: -9.88px; 788 | } 789 | 790 | .sm\\\\:matrix-0 { 791 | display: grid; 792 | grid-template-columns: repeat(1, minmax(auto,1fr)); 793 | } 794 | 795 | .sm\\\\:matrix-1 { 796 | display: grid; 797 | grid-template-columns: repeat(1, minmax(auto,1fr)); 798 | } 799 | 800 | .sm\\\\:matrix-2 { 801 | display: grid; 802 | grid-template-columns: repeat(2, minmax(auto,1fr)); 803 | } 804 | 805 | .sm\\\\:matrix-3 { 806 | display: grid; 807 | grid-template-columns: repeat(3, minmax(auto,1fr)); 808 | } 809 | 810 | .sm\\\\:matrix-4 { 811 | display: grid; 812 | grid-template-columns: repeat(4, minmax(auto,1fr)); 813 | } 814 | 815 | .sm\\\\:matrix-5 { 816 | display: grid; 817 | grid-template-columns: repeat(5, minmax(auto,1fr)); 818 | } 819 | 820 | .sm\\\\:matrix-6 { 821 | display: grid; 822 | grid-template-columns: repeat(6, minmax(auto,1fr)); 823 | } 824 | 825 | .sm\\\\:matrix-row-h-0 { 826 | grid-auto-rows: minmax(0px, auto); 827 | } 828 | 829 | .sm\\\\:matrix-gap-0 { 830 | grid-row-gap: 0px; 831 | grid-column-gap: 0px; 832 | } 833 | 834 | .sm\\\\:matrix-gap-x-0 { 835 | grid-column-gap: 0px; 836 | } 837 | 838 | .sm\\\\:matrix-gap-y-0 { 839 | grid-row-gap: 0px; 840 | } 841 | 842 | .sm\\\\:matrix-row-h-1 { 843 | grid-auto-rows: minmax(10px, auto); 844 | } 845 | 846 | .sm\\\\:matrix-gap-1 { 847 | grid-row-gap: 10px; 848 | grid-column-gap: 10px; 849 | } 850 | 851 | .sm\\\\:matrix-gap-x-1 { 852 | grid-column-gap: 10px; 853 | } 854 | 855 | .sm\\\\:matrix-gap-y-1 { 856 | grid-row-gap: 10px; 857 | } 858 | 859 | .sm\\\\:matrix-row-h-2 { 860 | grid-auto-rows: minmax(20px, auto); 861 | } 862 | 863 | .sm\\\\:matrix-gap-2 { 864 | grid-row-gap: 20px; 865 | grid-column-gap: 20px; 866 | } 867 | 868 | .sm\\\\:matrix-gap-x-2 { 869 | grid-column-gap: 20px; 870 | } 871 | 872 | .sm\\\\:matrix-gap-y-2 { 873 | grid-row-gap: 20px; 874 | } 875 | 876 | .sm\\\\:cell-start-x-1 { 877 | grid-column-start: 1 !important; 878 | } 879 | 880 | .sm\\\\:cell-span-x-1 { 881 | grid-column: auto / span 1; 882 | } 883 | 884 | .sm\\\\:cell-start-y-1 { 885 | grid-row-start: 1 !important; 886 | } 887 | 888 | .sm\\\\:cell-span-y-1 { 889 | grid-row: auto / span 1; 890 | } 891 | 892 | .sm\\\\:cell-start-x-1 { 893 | grid-column-start: 1 !important; 894 | } 895 | 896 | .sm\\\\:cell-span-x-1 { 897 | grid-column: auto / span 1; 898 | } 899 | 900 | .sm\\\\:cell-start-y-1 { 901 | grid-row-start: 1 !important; 902 | } 903 | 904 | .sm\\\\:cell-span-y-1 { 905 | grid-row: auto / span 1; 906 | } 907 | 908 | .sm\\\\:cell-start-x-2 { 909 | grid-column-start: 2 !important; 910 | } 911 | 912 | .sm\\\\:cell-span-x-2 { 913 | grid-column: auto / span 2; 914 | } 915 | 916 | .sm\\\\:cell-start-y-2 { 917 | grid-row-start: 2 !important; 918 | } 919 | 920 | .sm\\\\:cell-span-y-2 { 921 | grid-row: auto / span 2; 922 | } 923 | 924 | .sm\\\\:cell-start-x-3 { 925 | grid-column-start: 3 !important; 926 | } 927 | 928 | .sm\\\\:cell-span-x-3 { 929 | grid-column: auto / span 3; 930 | } 931 | 932 | .sm\\\\:cell-start-y-3 { 933 | grid-row-start: 3 !important; 934 | } 935 | 936 | .sm\\\\:cell-span-y-3 { 937 | grid-row: auto / span 3; 938 | } 939 | 940 | .sm\\\\:cell-start-x-4 { 941 | grid-column-start: 4 !important; 942 | } 943 | 944 | .sm\\\\:cell-span-x-4 { 945 | grid-column: auto / span 4; 946 | } 947 | 948 | .sm\\\\:cell-start-y-4 { 949 | grid-row-start: 4 !important; 950 | } 951 | 952 | .sm\\\\:cell-span-y-4 { 953 | grid-row: auto / span 4; 954 | } 955 | 956 | .sm\\\\:cell-start-x-5 { 957 | grid-column-start: 5 !important; 958 | } 959 | 960 | .sm\\\\:cell-span-x-5 { 961 | grid-column: auto / span 5; 962 | } 963 | 964 | .sm\\\\:cell-start-y-5 { 965 | grid-row-start: 5 !important; 966 | } 967 | 968 | .sm\\\\:cell-span-y-5 { 969 | grid-row: auto / span 5; 970 | } 971 | 972 | .sm\\\\:cell-start-x-6 { 973 | grid-column-start: 6 !important; 974 | } 975 | 976 | .sm\\\\:cell-span-x-6 { 977 | grid-column: auto / span 6; 978 | } 979 | 980 | .sm\\\\:cell-start-y-6 { 981 | grid-row-start: 6 !important; 982 | } 983 | 984 | .sm\\\\:cell-span-y-6 { 985 | grid-row: auto / span 6; 986 | } 987 | }" 988 | `; 989 | 990 | exports[`measure styles 1`] = ` 991 | ".font-sans-400 { 992 | font-family: \\"IBM Plex Sans\\", sans-serif; 993 | font-weight: 400; 994 | font-style: normal; 995 | display: block; 996 | } 997 | 998 | .font-sans-400::before, .font-sans-400::after { 999 | content: ''; 1000 | display: block; 1001 | height: 0; 1002 | } 1003 | 1004 | .font-sans-400.text-0\\\\/0 { 1005 | font-size: 10px; 1006 | line-height: 6.9799999999999995px; 1007 | padding-top: 0.4px; 1008 | padding-bottom: 0.4px; 1009 | } 1010 | 1011 | .font-sans-400.text-0\\\\/0::before { 1012 | margin-top: -0.6599999999999998px; 1013 | } 1014 | 1015 | .font-sans-400.text-0\\\\/0::after { 1016 | margin-bottom: -0.1399999999999998px; 1017 | } 1018 | 1019 | .font-sans-400.text-0\\\\/1 { 1020 | font-size: 10px; 1021 | line-height: 16.98px; 1022 | padding-top: 0.4px; 1023 | padding-bottom: 0.4px; 1024 | } 1025 | 1026 | .font-sans-400.text-0\\\\/1::before { 1027 | margin-top: -5.66px; 1028 | } 1029 | 1030 | .font-sans-400.text-0\\\\/1::after { 1031 | margin-bottom: -5.140000000000001px; 1032 | } 1033 | 1034 | .font-sans-400.text-0\\\\/2 { 1035 | font-size: 10px; 1036 | line-height: 26.98px; 1037 | padding-top: 0.4px; 1038 | padding-bottom: 0.4px; 1039 | } 1040 | 1041 | .font-sans-400.text-0\\\\/2::before { 1042 | margin-top: -10.66px; 1043 | } 1044 | 1045 | .font-sans-400.text-0\\\\/2::after { 1046 | margin-bottom: -10.14px; 1047 | } 1048 | 1049 | .font-sans-400.text-1\\\\/0 { 1050 | font-size: 20px; 1051 | line-height: 13.959999999999999px; 1052 | padding-top: 0.4px; 1053 | padding-bottom: 0.4px; 1054 | } 1055 | 1056 | .font-sans-400.text-1\\\\/0::before { 1057 | margin-top: -0.9199999999999996px; 1058 | } 1059 | 1060 | .font-sans-400.text-1\\\\/0::after { 1061 | margin-bottom: 0.12000000000000044px; 1062 | } 1063 | 1064 | .font-sans-400.text-1\\\\/1 { 1065 | font-size: 20px; 1066 | line-height: 23.96px; 1067 | padding-top: 0.4px; 1068 | padding-bottom: 0.4px; 1069 | } 1070 | 1071 | .font-sans-400.text-1\\\\/1::before { 1072 | margin-top: -5.920000000000001px; 1073 | } 1074 | 1075 | .font-sans-400.text-1\\\\/1::after { 1076 | margin-bottom: -4.880000000000001px; 1077 | } 1078 | 1079 | .font-sans-400.text-1\\\\/2 { 1080 | font-size: 20px; 1081 | line-height: 33.96px; 1082 | padding-top: 0.4px; 1083 | padding-bottom: 0.4px; 1084 | } 1085 | 1086 | .font-sans-400.text-1\\\\/2::before { 1087 | margin-top: -10.92px; 1088 | } 1089 | 1090 | .font-sans-400.text-1\\\\/2::after { 1091 | margin-bottom: -9.88px; 1092 | } 1093 | 1094 | .measure-0 { 1095 | max-width: 10ch; 1096 | } 1097 | 1098 | .measure-1 { 1099 | max-width: 20ch; 1100 | } 1101 | 1102 | @media (min-width: 640px) { 1103 | .font-sans-400.sm\\\\:text-0\\\\/0 { 1104 | font-size: 10px; 1105 | line-height: 6.9799999999999995px; 1106 | padding-top: 0.4px; 1107 | padding-bottom: 0.4px; 1108 | } 1109 | 1110 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 1111 | margin-top: -0.6599999999999998px; 1112 | } 1113 | 1114 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 1115 | margin-bottom: -0.1399999999999998px; 1116 | } 1117 | 1118 | .font-sans-400.sm\\\\:text-0\\\\/1 { 1119 | font-size: 10px; 1120 | line-height: 16.98px; 1121 | padding-top: 0.4px; 1122 | padding-bottom: 0.4px; 1123 | } 1124 | 1125 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 1126 | margin-top: -5.66px; 1127 | } 1128 | 1129 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 1130 | margin-bottom: -5.140000000000001px; 1131 | } 1132 | 1133 | .font-sans-400.sm\\\\:text-0\\\\/2 { 1134 | font-size: 10px; 1135 | line-height: 26.98px; 1136 | padding-top: 0.4px; 1137 | padding-bottom: 0.4px; 1138 | } 1139 | 1140 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 1141 | margin-top: -10.66px; 1142 | } 1143 | 1144 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 1145 | margin-bottom: -10.14px; 1146 | } 1147 | 1148 | .font-sans-400.sm\\\\:text-1\\\\/0 { 1149 | font-size: 20px; 1150 | line-height: 13.959999999999999px; 1151 | padding-top: 0.4px; 1152 | padding-bottom: 0.4px; 1153 | } 1154 | 1155 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 1156 | margin-top: -0.9199999999999996px; 1157 | } 1158 | 1159 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 1160 | margin-bottom: 0.12000000000000044px; 1161 | } 1162 | 1163 | .font-sans-400.sm\\\\:text-1\\\\/1 { 1164 | font-size: 20px; 1165 | line-height: 23.96px; 1166 | padding-top: 0.4px; 1167 | padding-bottom: 0.4px; 1168 | } 1169 | 1170 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 1171 | margin-top: -5.920000000000001px; 1172 | } 1173 | 1174 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 1175 | margin-bottom: -4.880000000000001px; 1176 | } 1177 | 1178 | .font-sans-400.sm\\\\:text-1\\\\/2 { 1179 | font-size: 20px; 1180 | line-height: 33.96px; 1181 | padding-top: 0.4px; 1182 | padding-bottom: 0.4px; 1183 | } 1184 | 1185 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 1186 | margin-top: -10.92px; 1187 | } 1188 | 1189 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 1190 | margin-bottom: -9.88px; 1191 | } 1192 | 1193 | .sm\\\\:measure-0 { 1194 | max-width: 10ch; 1195 | } 1196 | 1197 | .sm\\\\:measure-1 { 1198 | max-width: 20ch; 1199 | } 1200 | }" 1201 | `; 1202 | 1203 | exports[`rhythm styles 1`] = ` 1204 | ".font-sans-400 { 1205 | font-family: \\"IBM Plex Sans\\", sans-serif; 1206 | font-weight: 400; 1207 | font-style: normal; 1208 | display: block; 1209 | } 1210 | 1211 | .font-sans-400::before, .font-sans-400::after { 1212 | content: ''; 1213 | display: block; 1214 | height: 0; 1215 | } 1216 | 1217 | .font-sans-400.text-0\\\\/0 { 1218 | font-size: 10px; 1219 | line-height: 6.9799999999999995px; 1220 | padding-top: 0.4px; 1221 | padding-bottom: 0.4px; 1222 | } 1223 | 1224 | .font-sans-400.text-0\\\\/0::before { 1225 | margin-top: -0.6599999999999998px; 1226 | } 1227 | 1228 | .font-sans-400.text-0\\\\/0::after { 1229 | margin-bottom: -0.1399999999999998px; 1230 | } 1231 | 1232 | .font-sans-400.text-0\\\\/1 { 1233 | font-size: 10px; 1234 | line-height: 16.98px; 1235 | padding-top: 0.4px; 1236 | padding-bottom: 0.4px; 1237 | } 1238 | 1239 | .font-sans-400.text-0\\\\/1::before { 1240 | margin-top: -5.66px; 1241 | } 1242 | 1243 | .font-sans-400.text-0\\\\/1::after { 1244 | margin-bottom: -5.140000000000001px; 1245 | } 1246 | 1247 | .font-sans-400.text-0\\\\/2 { 1248 | font-size: 10px; 1249 | line-height: 26.98px; 1250 | padding-top: 0.4px; 1251 | padding-bottom: 0.4px; 1252 | } 1253 | 1254 | .font-sans-400.text-0\\\\/2::before { 1255 | margin-top: -10.66px; 1256 | } 1257 | 1258 | .font-sans-400.text-0\\\\/2::after { 1259 | margin-bottom: -10.14px; 1260 | } 1261 | 1262 | .font-sans-400.text-1\\\\/0 { 1263 | font-size: 20px; 1264 | line-height: 13.959999999999999px; 1265 | padding-top: 0.4px; 1266 | padding-bottom: 0.4px; 1267 | } 1268 | 1269 | .font-sans-400.text-1\\\\/0::before { 1270 | margin-top: -0.9199999999999996px; 1271 | } 1272 | 1273 | .font-sans-400.text-1\\\\/0::after { 1274 | margin-bottom: 0.12000000000000044px; 1275 | } 1276 | 1277 | .font-sans-400.text-1\\\\/1 { 1278 | font-size: 20px; 1279 | line-height: 23.96px; 1280 | padding-top: 0.4px; 1281 | padding-bottom: 0.4px; 1282 | } 1283 | 1284 | .font-sans-400.text-1\\\\/1::before { 1285 | margin-top: -5.920000000000001px; 1286 | } 1287 | 1288 | .font-sans-400.text-1\\\\/1::after { 1289 | margin-bottom: -4.880000000000001px; 1290 | } 1291 | 1292 | .font-sans-400.text-1\\\\/2 { 1293 | font-size: 20px; 1294 | line-height: 33.96px; 1295 | padding-top: 0.4px; 1296 | padding-bottom: 0.4px; 1297 | } 1298 | 1299 | .font-sans-400.text-1\\\\/2::before { 1300 | margin-top: -10.92px; 1301 | } 1302 | 1303 | .font-sans-400.text-1\\\\/2::after { 1304 | margin-bottom: -9.88px; 1305 | } 1306 | 1307 | .rhythm-0 > * + * { 1308 | margin-top: 0px; 1309 | } 1310 | 1311 | .rhythm-y-0 > * + * { 1312 | margin-top: 0px; 1313 | } 1314 | 1315 | .rhythm-x-0 > * + * { 1316 | margin-left: 0px; 1317 | } 1318 | 1319 | .rhythm-1 > * + * { 1320 | margin-top: 10px; 1321 | } 1322 | 1323 | .rhythm-y-1 > * + * { 1324 | margin-top: 10px; 1325 | } 1326 | 1327 | .rhythm-x-1 > * + * { 1328 | margin-left: 10px; 1329 | } 1330 | 1331 | .rhythm-2 > * + * { 1332 | margin-top: 20px; 1333 | } 1334 | 1335 | .rhythm-y-2 > * + * { 1336 | margin-top: 20px; 1337 | } 1338 | 1339 | .rhythm-x-2 > * + * { 1340 | margin-left: 20px; 1341 | } 1342 | 1343 | @media (min-width: 640px) { 1344 | .font-sans-400.sm\\\\:text-0\\\\/0 { 1345 | font-size: 10px; 1346 | line-height: 6.9799999999999995px; 1347 | padding-top: 0.4px; 1348 | padding-bottom: 0.4px; 1349 | } 1350 | 1351 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 1352 | margin-top: -0.6599999999999998px; 1353 | } 1354 | 1355 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 1356 | margin-bottom: -0.1399999999999998px; 1357 | } 1358 | 1359 | .font-sans-400.sm\\\\:text-0\\\\/1 { 1360 | font-size: 10px; 1361 | line-height: 16.98px; 1362 | padding-top: 0.4px; 1363 | padding-bottom: 0.4px; 1364 | } 1365 | 1366 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 1367 | margin-top: -5.66px; 1368 | } 1369 | 1370 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 1371 | margin-bottom: -5.140000000000001px; 1372 | } 1373 | 1374 | .font-sans-400.sm\\\\:text-0\\\\/2 { 1375 | font-size: 10px; 1376 | line-height: 26.98px; 1377 | padding-top: 0.4px; 1378 | padding-bottom: 0.4px; 1379 | } 1380 | 1381 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 1382 | margin-top: -10.66px; 1383 | } 1384 | 1385 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 1386 | margin-bottom: -10.14px; 1387 | } 1388 | 1389 | .font-sans-400.sm\\\\:text-1\\\\/0 { 1390 | font-size: 20px; 1391 | line-height: 13.959999999999999px; 1392 | padding-top: 0.4px; 1393 | padding-bottom: 0.4px; 1394 | } 1395 | 1396 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 1397 | margin-top: -0.9199999999999996px; 1398 | } 1399 | 1400 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 1401 | margin-bottom: 0.12000000000000044px; 1402 | } 1403 | 1404 | .font-sans-400.sm\\\\:text-1\\\\/1 { 1405 | font-size: 20px; 1406 | line-height: 23.96px; 1407 | padding-top: 0.4px; 1408 | padding-bottom: 0.4px; 1409 | } 1410 | 1411 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 1412 | margin-top: -5.920000000000001px; 1413 | } 1414 | 1415 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 1416 | margin-bottom: -4.880000000000001px; 1417 | } 1418 | 1419 | .font-sans-400.sm\\\\:text-1\\\\/2 { 1420 | font-size: 20px; 1421 | line-height: 33.96px; 1422 | padding-top: 0.4px; 1423 | padding-bottom: 0.4px; 1424 | } 1425 | 1426 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 1427 | margin-top: -10.92px; 1428 | } 1429 | 1430 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 1431 | margin-bottom: -9.88px; 1432 | } 1433 | 1434 | .sm\\\\:rhythm-0 > * + * { 1435 | margin-top: 0px; 1436 | } 1437 | 1438 | .sm\\\\:rhythm-y-0 > * + * { 1439 | margin-top: 0px; 1440 | } 1441 | 1442 | .sm\\\\:rhythm-x-0 > * + * { 1443 | margin-left: 0px; 1444 | } 1445 | 1446 | .sm\\\\:rhythm-1 > * + * { 1447 | margin-top: 10px; 1448 | } 1449 | 1450 | .sm\\\\:rhythm-y-1 > * + * { 1451 | margin-top: 10px; 1452 | } 1453 | 1454 | .sm\\\\:rhythm-x-1 > * + * { 1455 | margin-left: 10px; 1456 | } 1457 | 1458 | .sm\\\\:rhythm-2 > * + * { 1459 | margin-top: 20px; 1460 | } 1461 | 1462 | .sm\\\\:rhythm-y-2 > * + * { 1463 | margin-top: 20px; 1464 | } 1465 | 1466 | .sm\\\\:rhythm-x-2 > * + * { 1467 | margin-left: 20px; 1468 | } 1469 | }" 1470 | `; 1471 | 1472 | exports[`use px 1`] = ` 1473 | ".font-sans-400 { 1474 | font-family: \\"IBM Plex Sans\\", sans-serif; 1475 | font-weight: 400; 1476 | font-style: normal; 1477 | display: block; 1478 | } 1479 | 1480 | .font-sans-400::before, .font-sans-400::after { 1481 | content: ''; 1482 | display: block; 1483 | height: 0; 1484 | } 1485 | 1486 | .font-sans-400.text-0\\\\/0 { 1487 | font-size: 10px; 1488 | line-height: 10px; 1489 | padding-top: 3.42px; 1490 | padding-bottom: 0.4px; 1491 | } 1492 | 1493 | .font-sans-400.text-0\\\\/0::before { 1494 | margin-top: -2.17px; 1495 | } 1496 | 1497 | .font-sans-400.text-0\\\\/0::after { 1498 | margin-bottom: -1.65px; 1499 | } 1500 | 1501 | .font-sans-400.text-0\\\\/1 { 1502 | font-size: 10px; 1503 | line-height: 20px; 1504 | padding-top: 3.4199999999999995px; 1505 | padding-bottom: 0.4px; 1506 | } 1507 | 1508 | .font-sans-400.text-0\\\\/1::before { 1509 | margin-top: -7.17px; 1510 | } 1511 | 1512 | .font-sans-400.text-0\\\\/1::after { 1513 | margin-bottom: -6.65px; 1514 | } 1515 | 1516 | .font-sans-400.text-0\\\\/2 { 1517 | font-size: 10px; 1518 | line-height: 30px; 1519 | padding-top: 3.4199999999999995px; 1520 | padding-bottom: 0.4px; 1521 | } 1522 | 1523 | .font-sans-400.text-0\\\\/2::before { 1524 | margin-top: -12.17px; 1525 | } 1526 | 1527 | .font-sans-400.text-0\\\\/2::after { 1528 | margin-bottom: -11.65px; 1529 | } 1530 | 1531 | .font-sans-400.text-1\\\\/0 { 1532 | font-size: 20px; 1533 | line-height: 10px; 1534 | padding-top: -3.56px; 1535 | padding-bottom: 0.4px; 1536 | } 1537 | 1538 | .font-sans-400.text-1\\\\/0::before { 1539 | margin-top: 1.06px; 1540 | } 1541 | 1542 | .font-sans-400.text-1\\\\/0::after { 1543 | margin-bottom: 2.1px; 1544 | } 1545 | 1546 | .font-sans-400.text-1\\\\/1 { 1547 | font-size: 20px; 1548 | line-height: 20px; 1549 | padding-top: 6.44px; 1550 | padding-bottom: 0.4px; 1551 | } 1552 | 1553 | .font-sans-400.text-1\\\\/1::before { 1554 | margin-top: -3.94px; 1555 | } 1556 | 1557 | .font-sans-400.text-1\\\\/1::after { 1558 | margin-bottom: -2.9px; 1559 | } 1560 | 1561 | .font-sans-400.text-1\\\\/2 { 1562 | font-size: 20px; 1563 | line-height: 30px; 1564 | padding-top: 6.4399999999999995px; 1565 | padding-bottom: 0.4px; 1566 | } 1567 | 1568 | .font-sans-400.text-1\\\\/2::before { 1569 | margin-top: -8.94px; 1570 | } 1571 | 1572 | .font-sans-400.text-1\\\\/2::after { 1573 | margin-bottom: -7.9px; 1574 | } 1575 | 1576 | .bg-baseline { 1577 | position: relative; 1578 | background-repeat: repeat; 1579 | background-image: linear-gradient( 1580 | rgba(255, 0, 255, 0.3) 1px, 1581 | transparent 0 1582 | ); 1583 | background-size: 100% 10px; 1584 | } 1585 | 1586 | .measure-0 { 1587 | max-width: 10ch; 1588 | } 1589 | 1590 | .measure-1 { 1591 | max-width: 20ch; 1592 | } 1593 | 1594 | .rhythm-0 > * + * { 1595 | margin-top: 0px; 1596 | } 1597 | 1598 | .rhythm-y-0 > * + * { 1599 | margin-top: 0px; 1600 | } 1601 | 1602 | .rhythm-x-0 > * + * { 1603 | margin-left: 0px; 1604 | } 1605 | 1606 | .rhythm-1 > * + * { 1607 | margin-top: 10px; 1608 | } 1609 | 1610 | .rhythm-y-1 > * + * { 1611 | margin-top: 10px; 1612 | } 1613 | 1614 | .rhythm-x-1 > * + * { 1615 | margin-left: 10px; 1616 | } 1617 | 1618 | .rhythm-2 > * + * { 1619 | margin-top: 20px; 1620 | } 1621 | 1622 | .rhythm-y-2 > * + * { 1623 | margin-top: 20px; 1624 | } 1625 | 1626 | .rhythm-x-2 > * + * { 1627 | margin-left: 20px; 1628 | } 1629 | 1630 | .matrix-0 { 1631 | display: grid; 1632 | grid-template-columns: repeat(1, minmax(auto,1fr)); 1633 | } 1634 | 1635 | .matrix-1 { 1636 | display: grid; 1637 | grid-template-columns: repeat(1, minmax(auto,1fr)); 1638 | } 1639 | 1640 | .matrix-2 { 1641 | display: grid; 1642 | grid-template-columns: repeat(2, minmax(auto,1fr)); 1643 | } 1644 | 1645 | .matrix-3 { 1646 | display: grid; 1647 | grid-template-columns: repeat(3, minmax(auto,1fr)); 1648 | } 1649 | 1650 | .matrix-4 { 1651 | display: grid; 1652 | grid-template-columns: repeat(4, minmax(auto,1fr)); 1653 | } 1654 | 1655 | .matrix-5 { 1656 | display: grid; 1657 | grid-template-columns: repeat(5, minmax(auto,1fr)); 1658 | } 1659 | 1660 | .matrix-6 { 1661 | display: grid; 1662 | grid-template-columns: repeat(6, minmax(auto,1fr)); 1663 | } 1664 | 1665 | .matrix-row-h-0 { 1666 | grid-auto-rows: minmax(0px, auto); 1667 | } 1668 | 1669 | .matrix-gap-0 { 1670 | grid-row-gap: 0px; 1671 | grid-column-gap: 0px; 1672 | } 1673 | 1674 | .matrix-gap-x-0 { 1675 | grid-column-gap: 0px; 1676 | } 1677 | 1678 | .matrix-gap-y-0 { 1679 | grid-row-gap: 0px; 1680 | } 1681 | 1682 | .matrix-row-h-1 { 1683 | grid-auto-rows: minmax(10px, auto); 1684 | } 1685 | 1686 | .matrix-gap-1 { 1687 | grid-row-gap: 10px; 1688 | grid-column-gap: 10px; 1689 | } 1690 | 1691 | .matrix-gap-x-1 { 1692 | grid-column-gap: 10px; 1693 | } 1694 | 1695 | .matrix-gap-y-1 { 1696 | grid-row-gap: 10px; 1697 | } 1698 | 1699 | .matrix-row-h-2 { 1700 | grid-auto-rows: minmax(20px, auto); 1701 | } 1702 | 1703 | .matrix-gap-2 { 1704 | grid-row-gap: 20px; 1705 | grid-column-gap: 20px; 1706 | } 1707 | 1708 | .matrix-gap-x-2 { 1709 | grid-column-gap: 20px; 1710 | } 1711 | 1712 | .matrix-gap-y-2 { 1713 | grid-row-gap: 20px; 1714 | } 1715 | 1716 | .cell-start-x-1 { 1717 | grid-column-start: 1 !important; 1718 | } 1719 | 1720 | .cell-span-x-1 { 1721 | grid-column: auto / span 1; 1722 | } 1723 | 1724 | .cell-start-y-1 { 1725 | grid-row-start: 1 !important; 1726 | } 1727 | 1728 | .cell-span-y-1 { 1729 | grid-row: auto / span 1; 1730 | } 1731 | 1732 | .cell-start-x-1 { 1733 | grid-column-start: 1 !important; 1734 | } 1735 | 1736 | .cell-span-x-1 { 1737 | grid-column: auto / span 1; 1738 | } 1739 | 1740 | .cell-start-y-1 { 1741 | grid-row-start: 1 !important; 1742 | } 1743 | 1744 | .cell-span-y-1 { 1745 | grid-row: auto / span 1; 1746 | } 1747 | 1748 | .cell-start-x-2 { 1749 | grid-column-start: 2 !important; 1750 | } 1751 | 1752 | .cell-span-x-2 { 1753 | grid-column: auto / span 2; 1754 | } 1755 | 1756 | .cell-start-y-2 { 1757 | grid-row-start: 2 !important; 1758 | } 1759 | 1760 | .cell-span-y-2 { 1761 | grid-row: auto / span 2; 1762 | } 1763 | 1764 | .cell-start-x-3 { 1765 | grid-column-start: 3 !important; 1766 | } 1767 | 1768 | .cell-span-x-3 { 1769 | grid-column: auto / span 3; 1770 | } 1771 | 1772 | .cell-start-y-3 { 1773 | grid-row-start: 3 !important; 1774 | } 1775 | 1776 | .cell-span-y-3 { 1777 | grid-row: auto / span 3; 1778 | } 1779 | 1780 | .cell-start-x-4 { 1781 | grid-column-start: 4 !important; 1782 | } 1783 | 1784 | .cell-span-x-4 { 1785 | grid-column: auto / span 4; 1786 | } 1787 | 1788 | .cell-start-y-4 { 1789 | grid-row-start: 4 !important; 1790 | } 1791 | 1792 | .cell-span-y-4 { 1793 | grid-row: auto / span 4; 1794 | } 1795 | 1796 | .cell-start-x-5 { 1797 | grid-column-start: 5 !important; 1798 | } 1799 | 1800 | .cell-span-x-5 { 1801 | grid-column: auto / span 5; 1802 | } 1803 | 1804 | .cell-start-y-5 { 1805 | grid-row-start: 5 !important; 1806 | } 1807 | 1808 | .cell-span-y-5 { 1809 | grid-row: auto / span 5; 1810 | } 1811 | 1812 | .cell-start-x-6 { 1813 | grid-column-start: 6 !important; 1814 | } 1815 | 1816 | .cell-span-x-6 { 1817 | grid-column: auto / span 6; 1818 | } 1819 | 1820 | .cell-start-y-6 { 1821 | grid-row-start: 6 !important; 1822 | } 1823 | 1824 | .cell-span-y-6 { 1825 | grid-row: auto / span 6; 1826 | } 1827 | 1828 | @media (min-width: 640px) { 1829 | .font-sans-400.sm\\\\:text-0\\\\/0 { 1830 | font-size: 10px; 1831 | line-height: 10px; 1832 | padding-top: 3.42px; 1833 | padding-bottom: 0.4px; 1834 | } 1835 | 1836 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 1837 | margin-top: -2.17px; 1838 | } 1839 | 1840 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 1841 | margin-bottom: -1.65px; 1842 | } 1843 | 1844 | .font-sans-400.sm\\\\:text-0\\\\/1 { 1845 | font-size: 10px; 1846 | line-height: 20px; 1847 | padding-top: 3.4199999999999995px; 1848 | padding-bottom: 0.4px; 1849 | } 1850 | 1851 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 1852 | margin-top: -7.17px; 1853 | } 1854 | 1855 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 1856 | margin-bottom: -6.65px; 1857 | } 1858 | 1859 | .font-sans-400.sm\\\\:text-0\\\\/2 { 1860 | font-size: 10px; 1861 | line-height: 30px; 1862 | padding-top: 3.4199999999999995px; 1863 | padding-bottom: 0.4px; 1864 | } 1865 | 1866 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 1867 | margin-top: -12.17px; 1868 | } 1869 | 1870 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 1871 | margin-bottom: -11.65px; 1872 | } 1873 | 1874 | .font-sans-400.sm\\\\:text-1\\\\/0 { 1875 | font-size: 20px; 1876 | line-height: 10px; 1877 | padding-top: -3.56px; 1878 | padding-bottom: 0.4px; 1879 | } 1880 | 1881 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 1882 | margin-top: 1.06px; 1883 | } 1884 | 1885 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 1886 | margin-bottom: 2.1px; 1887 | } 1888 | 1889 | .font-sans-400.sm\\\\:text-1\\\\/1 { 1890 | font-size: 20px; 1891 | line-height: 20px; 1892 | padding-top: 6.44px; 1893 | padding-bottom: 0.4px; 1894 | } 1895 | 1896 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 1897 | margin-top: -3.94px; 1898 | } 1899 | 1900 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 1901 | margin-bottom: -2.9px; 1902 | } 1903 | 1904 | .font-sans-400.sm\\\\:text-1\\\\/2 { 1905 | font-size: 20px; 1906 | line-height: 30px; 1907 | padding-top: 6.4399999999999995px; 1908 | padding-bottom: 0.4px; 1909 | } 1910 | 1911 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 1912 | margin-top: -8.94px; 1913 | } 1914 | 1915 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 1916 | margin-bottom: -7.9px; 1917 | } 1918 | 1919 | .sm\\\\:measure-0 { 1920 | max-width: 10ch; 1921 | } 1922 | 1923 | .sm\\\\:measure-1 { 1924 | max-width: 20ch; 1925 | } 1926 | 1927 | .sm\\\\:rhythm-0 > * + * { 1928 | margin-top: 0px; 1929 | } 1930 | 1931 | .sm\\\\:rhythm-y-0 > * + * { 1932 | margin-top: 0px; 1933 | } 1934 | 1935 | .sm\\\\:rhythm-x-0 > * + * { 1936 | margin-left: 0px; 1937 | } 1938 | 1939 | .sm\\\\:rhythm-1 > * + * { 1940 | margin-top: 10px; 1941 | } 1942 | 1943 | .sm\\\\:rhythm-y-1 > * + * { 1944 | margin-top: 10px; 1945 | } 1946 | 1947 | .sm\\\\:rhythm-x-1 > * + * { 1948 | margin-left: 10px; 1949 | } 1950 | 1951 | .sm\\\\:rhythm-2 > * + * { 1952 | margin-top: 20px; 1953 | } 1954 | 1955 | .sm\\\\:rhythm-y-2 > * + * { 1956 | margin-top: 20px; 1957 | } 1958 | 1959 | .sm\\\\:rhythm-x-2 > * + * { 1960 | margin-left: 20px; 1961 | } 1962 | 1963 | .sm\\\\:matrix-0 { 1964 | display: grid; 1965 | grid-template-columns: repeat(1, minmax(auto,1fr)); 1966 | } 1967 | 1968 | .sm\\\\:matrix-1 { 1969 | display: grid; 1970 | grid-template-columns: repeat(1, minmax(auto,1fr)); 1971 | } 1972 | 1973 | .sm\\\\:matrix-2 { 1974 | display: grid; 1975 | grid-template-columns: repeat(2, minmax(auto,1fr)); 1976 | } 1977 | 1978 | .sm\\\\:matrix-3 { 1979 | display: grid; 1980 | grid-template-columns: repeat(3, minmax(auto,1fr)); 1981 | } 1982 | 1983 | .sm\\\\:matrix-4 { 1984 | display: grid; 1985 | grid-template-columns: repeat(4, minmax(auto,1fr)); 1986 | } 1987 | 1988 | .sm\\\\:matrix-5 { 1989 | display: grid; 1990 | grid-template-columns: repeat(5, minmax(auto,1fr)); 1991 | } 1992 | 1993 | .sm\\\\:matrix-6 { 1994 | display: grid; 1995 | grid-template-columns: repeat(6, minmax(auto,1fr)); 1996 | } 1997 | 1998 | .sm\\\\:matrix-row-h-0 { 1999 | grid-auto-rows: minmax(0px, auto); 2000 | } 2001 | 2002 | .sm\\\\:matrix-gap-0 { 2003 | grid-row-gap: 0px; 2004 | grid-column-gap: 0px; 2005 | } 2006 | 2007 | .sm\\\\:matrix-gap-x-0 { 2008 | grid-column-gap: 0px; 2009 | } 2010 | 2011 | .sm\\\\:matrix-gap-y-0 { 2012 | grid-row-gap: 0px; 2013 | } 2014 | 2015 | .sm\\\\:matrix-row-h-1 { 2016 | grid-auto-rows: minmax(10px, auto); 2017 | } 2018 | 2019 | .sm\\\\:matrix-gap-1 { 2020 | grid-row-gap: 10px; 2021 | grid-column-gap: 10px; 2022 | } 2023 | 2024 | .sm\\\\:matrix-gap-x-1 { 2025 | grid-column-gap: 10px; 2026 | } 2027 | 2028 | .sm\\\\:matrix-gap-y-1 { 2029 | grid-row-gap: 10px; 2030 | } 2031 | 2032 | .sm\\\\:matrix-row-h-2 { 2033 | grid-auto-rows: minmax(20px, auto); 2034 | } 2035 | 2036 | .sm\\\\:matrix-gap-2 { 2037 | grid-row-gap: 20px; 2038 | grid-column-gap: 20px; 2039 | } 2040 | 2041 | .sm\\\\:matrix-gap-x-2 { 2042 | grid-column-gap: 20px; 2043 | } 2044 | 2045 | .sm\\\\:matrix-gap-y-2 { 2046 | grid-row-gap: 20px; 2047 | } 2048 | 2049 | .sm\\\\:cell-start-x-1 { 2050 | grid-column-start: 1 !important; 2051 | } 2052 | 2053 | .sm\\\\:cell-span-x-1 { 2054 | grid-column: auto / span 1; 2055 | } 2056 | 2057 | .sm\\\\:cell-start-y-1 { 2058 | grid-row-start: 1 !important; 2059 | } 2060 | 2061 | .sm\\\\:cell-span-y-1 { 2062 | grid-row: auto / span 1; 2063 | } 2064 | 2065 | .sm\\\\:cell-start-x-1 { 2066 | grid-column-start: 1 !important; 2067 | } 2068 | 2069 | .sm\\\\:cell-span-x-1 { 2070 | grid-column: auto / span 1; 2071 | } 2072 | 2073 | .sm\\\\:cell-start-y-1 { 2074 | grid-row-start: 1 !important; 2075 | } 2076 | 2077 | .sm\\\\:cell-span-y-1 { 2078 | grid-row: auto / span 1; 2079 | } 2080 | 2081 | .sm\\\\:cell-start-x-2 { 2082 | grid-column-start: 2 !important; 2083 | } 2084 | 2085 | .sm\\\\:cell-span-x-2 { 2086 | grid-column: auto / span 2; 2087 | } 2088 | 2089 | .sm\\\\:cell-start-y-2 { 2090 | grid-row-start: 2 !important; 2091 | } 2092 | 2093 | .sm\\\\:cell-span-y-2 { 2094 | grid-row: auto / span 2; 2095 | } 2096 | 2097 | .sm\\\\:cell-start-x-3 { 2098 | grid-column-start: 3 !important; 2099 | } 2100 | 2101 | .sm\\\\:cell-span-x-3 { 2102 | grid-column: auto / span 3; 2103 | } 2104 | 2105 | .sm\\\\:cell-start-y-3 { 2106 | grid-row-start: 3 !important; 2107 | } 2108 | 2109 | .sm\\\\:cell-span-y-3 { 2110 | grid-row: auto / span 3; 2111 | } 2112 | 2113 | .sm\\\\:cell-start-x-4 { 2114 | grid-column-start: 4 !important; 2115 | } 2116 | 2117 | .sm\\\\:cell-span-x-4 { 2118 | grid-column: auto / span 4; 2119 | } 2120 | 2121 | .sm\\\\:cell-start-y-4 { 2122 | grid-row-start: 4 !important; 2123 | } 2124 | 2125 | .sm\\\\:cell-span-y-4 { 2126 | grid-row: auto / span 4; 2127 | } 2128 | 2129 | .sm\\\\:cell-start-x-5 { 2130 | grid-column-start: 5 !important; 2131 | } 2132 | 2133 | .sm\\\\:cell-span-x-5 { 2134 | grid-column: auto / span 5; 2135 | } 2136 | 2137 | .sm\\\\:cell-start-y-5 { 2138 | grid-row-start: 5 !important; 2139 | } 2140 | 2141 | .sm\\\\:cell-span-y-5 { 2142 | grid-row: auto / span 5; 2143 | } 2144 | 2145 | .sm\\\\:cell-start-x-6 { 2146 | grid-column-start: 6 !important; 2147 | } 2148 | 2149 | .sm\\\\:cell-span-x-6 { 2150 | grid-column: auto / span 6; 2151 | } 2152 | 2153 | .sm\\\\:cell-start-y-6 { 2154 | grid-row-start: 6 !important; 2155 | } 2156 | 2157 | .sm\\\\:cell-span-y-6 { 2158 | grid-row: auto / span 6; 2159 | } 2160 | }" 2161 | `; 2162 | 2163 | exports[`use rem 1`] = ` 2164 | ".font-sans-400 { 2165 | font-family: \\"IBM Plex Sans\\", sans-serif; 2166 | font-weight: 400; 2167 | font-style: normal; 2168 | display: block; 2169 | } 2170 | 2171 | .font-sans-400::before, .font-sans-400::after { 2172 | content: ''; 2173 | display: block; 2174 | height: 0; 2175 | } 2176 | 2177 | .font-sans-400.text-0\\\\/0 { 2178 | font-size: 1rem; 2179 | line-height: 1; 2180 | padding-top: 0.34199999999999997em; 2181 | padding-bottom: 0.04em; 2182 | } 2183 | 2184 | .font-sans-400.text-0\\\\/0::before { 2185 | margin-top: -0.217em; 2186 | } 2187 | 2188 | .font-sans-400.text-0\\\\/0::after { 2189 | margin-bottom: -0.16499999999999998em; 2190 | } 2191 | 2192 | .font-sans-400.text-0\\\\/1 { 2193 | font-size: 1rem; 2194 | line-height: 2; 2195 | padding-top: 0.34199999999999997em; 2196 | padding-bottom: 0.04em; 2197 | } 2198 | 2199 | .font-sans-400.text-0\\\\/1::before { 2200 | margin-top: -0.717em; 2201 | } 2202 | 2203 | .font-sans-400.text-0\\\\/1::after { 2204 | margin-bottom: -0.665em; 2205 | } 2206 | 2207 | .font-sans-400.text-0\\\\/2 { 2208 | font-size: 1rem; 2209 | line-height: 3; 2210 | padding-top: 0.34199999999999997em; 2211 | padding-bottom: 0.04em; 2212 | } 2213 | 2214 | .font-sans-400.text-0\\\\/2::before { 2215 | margin-top: -1.217em; 2216 | } 2217 | 2218 | .font-sans-400.text-0\\\\/2::after { 2219 | margin-bottom: -1.165em; 2220 | } 2221 | 2222 | .font-sans-400.text-1\\\\/0 { 2223 | font-size: 2rem; 2224 | line-height: 0.5; 2225 | padding-top: -0.178em; 2226 | padding-bottom: 0.02em; 2227 | } 2228 | 2229 | .font-sans-400.text-1\\\\/0::before { 2230 | margin-top: 0.053000000000000005em; 2231 | } 2232 | 2233 | .font-sans-400.text-1\\\\/0::after { 2234 | margin-bottom: 0.10500000000000001em; 2235 | } 2236 | 2237 | .font-sans-400.text-1\\\\/1 { 2238 | font-size: 2rem; 2239 | line-height: 1; 2240 | padding-top: 0.322em; 2241 | padding-bottom: 0.02em; 2242 | } 2243 | 2244 | .font-sans-400.text-1\\\\/1::before { 2245 | margin-top: -0.197em; 2246 | } 2247 | 2248 | .font-sans-400.text-1\\\\/1::after { 2249 | margin-bottom: -0.145em; 2250 | } 2251 | 2252 | .font-sans-400.text-1\\\\/2 { 2253 | font-size: 2rem; 2254 | line-height: 1.5; 2255 | padding-top: 0.32199999999999995em; 2256 | padding-bottom: 0.02em; 2257 | } 2258 | 2259 | .font-sans-400.text-1\\\\/2::before { 2260 | margin-top: -0.44699999999999995em; 2261 | } 2262 | 2263 | .font-sans-400.text-1\\\\/2::after { 2264 | margin-bottom: -0.395em; 2265 | } 2266 | 2267 | .bg-baseline { 2268 | position: relative; 2269 | background-repeat: repeat; 2270 | background-size: 100% 1rem; 2271 | background-image: linear-gradient( 2272 | rgba(255, 0, 255, 0.3) 1px, 2273 | transparent 0 2274 | ); 2275 | } 2276 | 2277 | .measure-0 { 2278 | max-width: 10ch; 2279 | } 2280 | 2281 | .measure-1 { 2282 | max-width: 20ch; 2283 | } 2284 | 2285 | .rhythm-0 > * + * { 2286 | margin-top: 0rem; 2287 | } 2288 | 2289 | .rhythm-y-0 > * + * { 2290 | margin-top: 0rem; 2291 | } 2292 | 2293 | .rhythm-x-0 > * + * { 2294 | margin-left: 0rem; 2295 | } 2296 | 2297 | .rhythm-1 > * + * { 2298 | margin-top: 1rem; 2299 | } 2300 | 2301 | .rhythm-y-1 > * + * { 2302 | margin-top: 1rem; 2303 | } 2304 | 2305 | .rhythm-x-1 > * + * { 2306 | margin-left: 1rem; 2307 | } 2308 | 2309 | .rhythm-2 > * + * { 2310 | margin-top: 2rem; 2311 | } 2312 | 2313 | .rhythm-y-2 > * + * { 2314 | margin-top: 2rem; 2315 | } 2316 | 2317 | .rhythm-x-2 > * + * { 2318 | margin-left: 2rem; 2319 | } 2320 | 2321 | .matrix-0 { 2322 | display: grid; 2323 | grid-template-columns: repeat(1, minmax(auto,1fr)); 2324 | } 2325 | 2326 | .matrix-1 { 2327 | display: grid; 2328 | grid-template-columns: repeat(1, minmax(auto,1fr)); 2329 | } 2330 | 2331 | .matrix-2 { 2332 | display: grid; 2333 | grid-template-columns: repeat(2, minmax(auto,1fr)); 2334 | } 2335 | 2336 | .matrix-3 { 2337 | display: grid; 2338 | grid-template-columns: repeat(3, minmax(auto,1fr)); 2339 | } 2340 | 2341 | .matrix-4 { 2342 | display: grid; 2343 | grid-template-columns: repeat(4, minmax(auto,1fr)); 2344 | } 2345 | 2346 | .matrix-5 { 2347 | display: grid; 2348 | grid-template-columns: repeat(5, minmax(auto,1fr)); 2349 | } 2350 | 2351 | .matrix-6 { 2352 | display: grid; 2353 | grid-template-columns: repeat(6, minmax(auto,1fr)); 2354 | } 2355 | 2356 | .matrix-row-h-0 { 2357 | grid-auto-rows: minmax(0rem, auto); 2358 | } 2359 | 2360 | .matrix-gap-0 { 2361 | grid-row-gap: 0rem; 2362 | grid-column-gap: 0rem; 2363 | } 2364 | 2365 | .matrix-gap-x-0 { 2366 | grid-column-gap: 0rem; 2367 | } 2368 | 2369 | .matrix-gap-y-0 { 2370 | grid-row-gap: 0rem; 2371 | } 2372 | 2373 | .matrix-row-h-1 { 2374 | grid-auto-rows: minmax(1rem, auto); 2375 | } 2376 | 2377 | .matrix-gap-1 { 2378 | grid-row-gap: 1rem; 2379 | grid-column-gap: 1rem; 2380 | } 2381 | 2382 | .matrix-gap-x-1 { 2383 | grid-column-gap: 1rem; 2384 | } 2385 | 2386 | .matrix-gap-y-1 { 2387 | grid-row-gap: 1rem; 2388 | } 2389 | 2390 | .matrix-row-h-2 { 2391 | grid-auto-rows: minmax(2rem, auto); 2392 | } 2393 | 2394 | .matrix-gap-2 { 2395 | grid-row-gap: 2rem; 2396 | grid-column-gap: 2rem; 2397 | } 2398 | 2399 | .matrix-gap-x-2 { 2400 | grid-column-gap: 2rem; 2401 | } 2402 | 2403 | .matrix-gap-y-2 { 2404 | grid-row-gap: 2rem; 2405 | } 2406 | 2407 | .cell-start-x-1 { 2408 | grid-column-start: 1 !important; 2409 | } 2410 | 2411 | .cell-span-x-1 { 2412 | grid-column: auto / span 1; 2413 | } 2414 | 2415 | .cell-start-y-1 { 2416 | grid-row-start: 1 !important; 2417 | } 2418 | 2419 | .cell-span-y-1 { 2420 | grid-row: auto / span 1; 2421 | } 2422 | 2423 | .cell-start-x-1 { 2424 | grid-column-start: 1 !important; 2425 | } 2426 | 2427 | .cell-span-x-1 { 2428 | grid-column: auto / span 1; 2429 | } 2430 | 2431 | .cell-start-y-1 { 2432 | grid-row-start: 1 !important; 2433 | } 2434 | 2435 | .cell-span-y-1 { 2436 | grid-row: auto / span 1; 2437 | } 2438 | 2439 | .cell-start-x-2 { 2440 | grid-column-start: 2 !important; 2441 | } 2442 | 2443 | .cell-span-x-2 { 2444 | grid-column: auto / span 2; 2445 | } 2446 | 2447 | .cell-start-y-2 { 2448 | grid-row-start: 2 !important; 2449 | } 2450 | 2451 | .cell-span-y-2 { 2452 | grid-row: auto / span 2; 2453 | } 2454 | 2455 | .cell-start-x-3 { 2456 | grid-column-start: 3 !important; 2457 | } 2458 | 2459 | .cell-span-x-3 { 2460 | grid-column: auto / span 3; 2461 | } 2462 | 2463 | .cell-start-y-3 { 2464 | grid-row-start: 3 !important; 2465 | } 2466 | 2467 | .cell-span-y-3 { 2468 | grid-row: auto / span 3; 2469 | } 2470 | 2471 | .cell-start-x-4 { 2472 | grid-column-start: 4 !important; 2473 | } 2474 | 2475 | .cell-span-x-4 { 2476 | grid-column: auto / span 4; 2477 | } 2478 | 2479 | .cell-start-y-4 { 2480 | grid-row-start: 4 !important; 2481 | } 2482 | 2483 | .cell-span-y-4 { 2484 | grid-row: auto / span 4; 2485 | } 2486 | 2487 | .cell-start-x-5 { 2488 | grid-column-start: 5 !important; 2489 | } 2490 | 2491 | .cell-span-x-5 { 2492 | grid-column: auto / span 5; 2493 | } 2494 | 2495 | .cell-start-y-5 { 2496 | grid-row-start: 5 !important; 2497 | } 2498 | 2499 | .cell-span-y-5 { 2500 | grid-row: auto / span 5; 2501 | } 2502 | 2503 | .cell-start-x-6 { 2504 | grid-column-start: 6 !important; 2505 | } 2506 | 2507 | .cell-span-x-6 { 2508 | grid-column: auto / span 6; 2509 | } 2510 | 2511 | .cell-start-y-6 { 2512 | grid-row-start: 6 !important; 2513 | } 2514 | 2515 | .cell-span-y-6 { 2516 | grid-row: auto / span 6; 2517 | } 2518 | 2519 | @media (min-width: 640px) { 2520 | .font-sans-400.sm\\\\:text-0\\\\/0 { 2521 | font-size: 1rem; 2522 | line-height: 1; 2523 | padding-top: 0.34199999999999997em; 2524 | padding-bottom: 0.04em; 2525 | } 2526 | 2527 | .font-sans-400.sm\\\\:text-0\\\\/0::before { 2528 | margin-top: -0.217em; 2529 | } 2530 | 2531 | .font-sans-400.sm\\\\:text-0\\\\/0::after { 2532 | margin-bottom: -0.16499999999999998em; 2533 | } 2534 | 2535 | .font-sans-400.sm\\\\:text-0\\\\/1 { 2536 | font-size: 1rem; 2537 | line-height: 2; 2538 | padding-top: 0.34199999999999997em; 2539 | padding-bottom: 0.04em; 2540 | } 2541 | 2542 | .font-sans-400.sm\\\\:text-0\\\\/1::before { 2543 | margin-top: -0.717em; 2544 | } 2545 | 2546 | .font-sans-400.sm\\\\:text-0\\\\/1::after { 2547 | margin-bottom: -0.665em; 2548 | } 2549 | 2550 | .font-sans-400.sm\\\\:text-0\\\\/2 { 2551 | font-size: 1rem; 2552 | line-height: 3; 2553 | padding-top: 0.34199999999999997em; 2554 | padding-bottom: 0.04em; 2555 | } 2556 | 2557 | .font-sans-400.sm\\\\:text-0\\\\/2::before { 2558 | margin-top: -1.217em; 2559 | } 2560 | 2561 | .font-sans-400.sm\\\\:text-0\\\\/2::after { 2562 | margin-bottom: -1.165em; 2563 | } 2564 | 2565 | .font-sans-400.sm\\\\:text-1\\\\/0 { 2566 | font-size: 2rem; 2567 | line-height: 0.5; 2568 | padding-top: -0.178em; 2569 | padding-bottom: 0.02em; 2570 | } 2571 | 2572 | .font-sans-400.sm\\\\:text-1\\\\/0::before { 2573 | margin-top: 0.053000000000000005em; 2574 | } 2575 | 2576 | .font-sans-400.sm\\\\:text-1\\\\/0::after { 2577 | margin-bottom: 0.10500000000000001em; 2578 | } 2579 | 2580 | .font-sans-400.sm\\\\:text-1\\\\/1 { 2581 | font-size: 2rem; 2582 | line-height: 1; 2583 | padding-top: 0.322em; 2584 | padding-bottom: 0.02em; 2585 | } 2586 | 2587 | .font-sans-400.sm\\\\:text-1\\\\/1::before { 2588 | margin-top: -0.197em; 2589 | } 2590 | 2591 | .font-sans-400.sm\\\\:text-1\\\\/1::after { 2592 | margin-bottom: -0.145em; 2593 | } 2594 | 2595 | .font-sans-400.sm\\\\:text-1\\\\/2 { 2596 | font-size: 2rem; 2597 | line-height: 1.5; 2598 | padding-top: 0.32199999999999995em; 2599 | padding-bottom: 0.02em; 2600 | } 2601 | 2602 | .font-sans-400.sm\\\\:text-1\\\\/2::before { 2603 | margin-top: -0.44699999999999995em; 2604 | } 2605 | 2606 | .font-sans-400.sm\\\\:text-1\\\\/2::after { 2607 | margin-bottom: -0.395em; 2608 | } 2609 | 2610 | .sm\\\\:measure-0 { 2611 | max-width: 10ch; 2612 | } 2613 | 2614 | .sm\\\\:measure-1 { 2615 | max-width: 20ch; 2616 | } 2617 | 2618 | .sm\\\\:rhythm-0 > * + * { 2619 | margin-top: 0rem; 2620 | } 2621 | 2622 | .sm\\\\:rhythm-y-0 > * + * { 2623 | margin-top: 0rem; 2624 | } 2625 | 2626 | .sm\\\\:rhythm-x-0 > * + * { 2627 | margin-left: 0rem; 2628 | } 2629 | 2630 | .sm\\\\:rhythm-1 > * + * { 2631 | margin-top: 1rem; 2632 | } 2633 | 2634 | .sm\\\\:rhythm-y-1 > * + * { 2635 | margin-top: 1rem; 2636 | } 2637 | 2638 | .sm\\\\:rhythm-x-1 > * + * { 2639 | margin-left: 1rem; 2640 | } 2641 | 2642 | .sm\\\\:rhythm-2 > * + * { 2643 | margin-top: 2rem; 2644 | } 2645 | 2646 | .sm\\\\:rhythm-y-2 > * + * { 2647 | margin-top: 2rem; 2648 | } 2649 | 2650 | .sm\\\\:rhythm-x-2 > * + * { 2651 | margin-left: 2rem; 2652 | } 2653 | 2654 | .sm\\\\:matrix-0 { 2655 | display: grid; 2656 | grid-template-columns: repeat(1, minmax(auto,1fr)); 2657 | } 2658 | 2659 | .sm\\\\:matrix-1 { 2660 | display: grid; 2661 | grid-template-columns: repeat(1, minmax(auto,1fr)); 2662 | } 2663 | 2664 | .sm\\\\:matrix-2 { 2665 | display: grid; 2666 | grid-template-columns: repeat(2, minmax(auto,1fr)); 2667 | } 2668 | 2669 | .sm\\\\:matrix-3 { 2670 | display: grid; 2671 | grid-template-columns: repeat(3, minmax(auto,1fr)); 2672 | } 2673 | 2674 | .sm\\\\:matrix-4 { 2675 | display: grid; 2676 | grid-template-columns: repeat(4, minmax(auto,1fr)); 2677 | } 2678 | 2679 | .sm\\\\:matrix-5 { 2680 | display: grid; 2681 | grid-template-columns: repeat(5, minmax(auto,1fr)); 2682 | } 2683 | 2684 | .sm\\\\:matrix-6 { 2685 | display: grid; 2686 | grid-template-columns: repeat(6, minmax(auto,1fr)); 2687 | } 2688 | 2689 | .sm\\\\:matrix-row-h-0 { 2690 | grid-auto-rows: minmax(0rem, auto); 2691 | } 2692 | 2693 | .sm\\\\:matrix-gap-0 { 2694 | grid-row-gap: 0rem; 2695 | grid-column-gap: 0rem; 2696 | } 2697 | 2698 | .sm\\\\:matrix-gap-x-0 { 2699 | grid-column-gap: 0rem; 2700 | } 2701 | 2702 | .sm\\\\:matrix-gap-y-0 { 2703 | grid-row-gap: 0rem; 2704 | } 2705 | 2706 | .sm\\\\:matrix-row-h-1 { 2707 | grid-auto-rows: minmax(1rem, auto); 2708 | } 2709 | 2710 | .sm\\\\:matrix-gap-1 { 2711 | grid-row-gap: 1rem; 2712 | grid-column-gap: 1rem; 2713 | } 2714 | 2715 | .sm\\\\:matrix-gap-x-1 { 2716 | grid-column-gap: 1rem; 2717 | } 2718 | 2719 | .sm\\\\:matrix-gap-y-1 { 2720 | grid-row-gap: 1rem; 2721 | } 2722 | 2723 | .sm\\\\:matrix-row-h-2 { 2724 | grid-auto-rows: minmax(2rem, auto); 2725 | } 2726 | 2727 | .sm\\\\:matrix-gap-2 { 2728 | grid-row-gap: 2rem; 2729 | grid-column-gap: 2rem; 2730 | } 2731 | 2732 | .sm\\\\:matrix-gap-x-2 { 2733 | grid-column-gap: 2rem; 2734 | } 2735 | 2736 | .sm\\\\:matrix-gap-y-2 { 2737 | grid-row-gap: 2rem; 2738 | } 2739 | 2740 | .sm\\\\:cell-start-x-1 { 2741 | grid-column-start: 1 !important; 2742 | } 2743 | 2744 | .sm\\\\:cell-span-x-1 { 2745 | grid-column: auto / span 1; 2746 | } 2747 | 2748 | .sm\\\\:cell-start-y-1 { 2749 | grid-row-start: 1 !important; 2750 | } 2751 | 2752 | .sm\\\\:cell-span-y-1 { 2753 | grid-row: auto / span 1; 2754 | } 2755 | 2756 | .sm\\\\:cell-start-x-1 { 2757 | grid-column-start: 1 !important; 2758 | } 2759 | 2760 | .sm\\\\:cell-span-x-1 { 2761 | grid-column: auto / span 1; 2762 | } 2763 | 2764 | .sm\\\\:cell-start-y-1 { 2765 | grid-row-start: 1 !important; 2766 | } 2767 | 2768 | .sm\\\\:cell-span-y-1 { 2769 | grid-row: auto / span 1; 2770 | } 2771 | 2772 | .sm\\\\:cell-start-x-2 { 2773 | grid-column-start: 2 !important; 2774 | } 2775 | 2776 | .sm\\\\:cell-span-x-2 { 2777 | grid-column: auto / span 2; 2778 | } 2779 | 2780 | .sm\\\\:cell-start-y-2 { 2781 | grid-row-start: 2 !important; 2782 | } 2783 | 2784 | .sm\\\\:cell-span-y-2 { 2785 | grid-row: auto / span 2; 2786 | } 2787 | 2788 | .sm\\\\:cell-start-x-3 { 2789 | grid-column-start: 3 !important; 2790 | } 2791 | 2792 | .sm\\\\:cell-span-x-3 { 2793 | grid-column: auto / span 3; 2794 | } 2795 | 2796 | .sm\\\\:cell-start-y-3 { 2797 | grid-row-start: 3 !important; 2798 | } 2799 | 2800 | .sm\\\\:cell-span-y-3 { 2801 | grid-row: auto / span 3; 2802 | } 2803 | 2804 | .sm\\\\:cell-start-x-4 { 2805 | grid-column-start: 4 !important; 2806 | } 2807 | 2808 | .sm\\\\:cell-span-x-4 { 2809 | grid-column: auto / span 4; 2810 | } 2811 | 2812 | .sm\\\\:cell-start-y-4 { 2813 | grid-row-start: 4 !important; 2814 | } 2815 | 2816 | .sm\\\\:cell-span-y-4 { 2817 | grid-row: auto / span 4; 2818 | } 2819 | 2820 | .sm\\\\:cell-start-x-5 { 2821 | grid-column-start: 5 !important; 2822 | } 2823 | 2824 | .sm\\\\:cell-span-x-5 { 2825 | grid-column: auto / span 5; 2826 | } 2827 | 2828 | .sm\\\\:cell-start-y-5 { 2829 | grid-row-start: 5 !important; 2830 | } 2831 | 2832 | .sm\\\\:cell-span-y-5 { 2833 | grid-row: auto / span 5; 2834 | } 2835 | 2836 | .sm\\\\:cell-start-x-6 { 2837 | grid-column-start: 6 !important; 2838 | } 2839 | 2840 | .sm\\\\:cell-span-x-6 { 2841 | grid-column: auto / span 6; 2842 | } 2843 | 2844 | .sm\\\\:cell-start-y-6 { 2845 | grid-row-start: 6 !important; 2846 | } 2847 | 2848 | .sm\\\\:cell-span-y-6 { 2849 | grid-row: auto / span 6; 2850 | } 2851 | }" 2852 | `; 2853 | -------------------------------------------------------------------------------- /plugin/src/__tests__/compositor.file.test.ts: -------------------------------------------------------------------------------- 1 | import { ICompositorConfig } from '../types'; 2 | import path from 'path'; 3 | import { merge } from '../utils'; 4 | import compositor from '../theme-compositor'; 5 | 6 | import compositorBaseConfig from './fixtures/compositor.config.js'; 7 | import tailwindConfig from './fixtures/tailwind.config.js'; 8 | 9 | const createConfig = config => { 10 | const compositorConfig: ICompositorConfig = merge( 11 | compositorBaseConfig, 12 | config 13 | ); 14 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 15 | return tailwindConfigComposed; 16 | }; 17 | 18 | test('transform with font files', () => { 19 | const tailwindConfig = createConfig({ 20 | fonts: [ 21 | { 22 | file: path.resolve( 23 | 'plugin/src/__tests__/', 24 | 'fixtures/inter/Inter-Regular.woff' 25 | ), 26 | key: 'sans-400', 27 | }, 28 | ], 29 | }); 30 | expect(tailwindConfig).toMatchSnapshot(); 31 | }); 32 | -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/compositor.config.js: -------------------------------------------------------------------------------- 1 | const root = 10; 2 | 3 | const baseline = 10; 4 | 5 | const leading = 2; 6 | 7 | const matrix = 6; 8 | 9 | const type = [10, 20]; 10 | 11 | const rhythm = [0, 1, 2]; 12 | 13 | const measure = [10, 20]; 14 | 15 | const fonts = [ 16 | { 17 | key: 'sans-400', 18 | familyName: 'IBM Plex Sans', 19 | fallback: 'sans-serif', 20 | upm: 1000, 21 | xHeight: 525, 22 | capHeight: 698, 23 | ascent: 1025, 24 | lineGap: 0, 25 | descent: -275, 26 | weight: 400, 27 | italic: false, 28 | }, 29 | ]; 30 | 31 | module.exports = { 32 | root, 33 | baseline, 34 | leading, 35 | matrix, 36 | type, 37 | rhythm, 38 | measure, 39 | fonts, 40 | options: { 41 | useRem: false, 42 | snap: true, 43 | type: true, 44 | rhythm: true, 45 | measure: true, 46 | matrix: true, 47 | xray: true, 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Black.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-BlackItalic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Bold.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-BoldItalic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-ExtraBold.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Italic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Medium.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-MediumItalic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-Regular.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-SemiBold.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/src/__tests__/fixtures/playfair/PlayfairDisplay-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /plugin/src/__tests__/fixtures/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [], 3 | target: 'relaxed', 4 | prefix: '', 5 | important: false, 6 | separator: ':', 7 | theme: { 8 | screens: { 9 | sm: '640px', 10 | }, 11 | colors: { 12 | transparent: 'transparent', 13 | current: 'currentColor', 14 | black: '#000', 15 | white: '#fff', 16 | }, 17 | spacing: { 18 | px: '1px', 19 | '0': '0', 20 | '1': '0.25rem', 21 | '2': '0.5rem', 22 | '3': '0.75rem', 23 | '4': '1rem', 24 | }, 25 | flex: { 26 | auto: '1 1 auto', 27 | }, 28 | fontFamily: { 29 | sans: ['system-ui'], 30 | }, 31 | fontSize: { 32 | base: '1rem', 33 | lg: '1.5rem', 34 | }, 35 | fontWeight: { 36 | normal: '400', 37 | bold: '700', 38 | }, 39 | letterSpacing: { 40 | normal: '0', 41 | wide: '0.025em', 42 | }, 43 | lineHeight: { 44 | none: '1', 45 | normal: '1.5', 46 | }, 47 | extend: { 48 | maxHeight: { 49 | '100': '100px', 50 | }, 51 | maxWidth: { 52 | '100': '100px', 53 | }, 54 | minHeight: { 55 | '100': '100px', 56 | }, 57 | minWidth: { 58 | '100': '100px', 59 | }, 60 | }, 61 | }, 62 | variants: { 63 | accessibility: [], 64 | alignContent: [], 65 | alignItems: [], 66 | alignSelf: [], 67 | appearance: [], 68 | backgroundAttachment: [], 69 | backgroundColor: [], 70 | backgroundOpacity: [], 71 | backgroundPosition: [], 72 | backgroundRepeat: [], 73 | backgroundSize: [], 74 | borderCollapse: [], 75 | borderColor: [], 76 | borderOpacity: [], 77 | borderRadius: [], 78 | borderStyle: [], 79 | borderWidth: [], 80 | boxShadow: [], 81 | boxSizing: [], 82 | cursor: [], 83 | display: [], 84 | divideColor: [], 85 | divideOpacity: [], 86 | divideWidth: [], 87 | fill: [], 88 | flex: [], 89 | flexDirection: [], 90 | flexGrow: [], 91 | flexShrink: [], 92 | flexWrap: [], 93 | float: [], 94 | clear: [], 95 | fontFamily: [], 96 | fontSize: [], 97 | fontSmoothing: [], 98 | fontStyle: [], 99 | fontWeight: [], 100 | height: [], 101 | inset: [], 102 | justifyContent: [], 103 | letterSpacing: [], 104 | lineHeight: [], 105 | listStylePosition: [], 106 | listStyleType: [], 107 | margin: [], 108 | maxHeight: [], 109 | maxWidth: [], 110 | minHeight: [], 111 | minWidth: [], 112 | objectFit: [], 113 | objectPosition: [], 114 | opacity: [], 115 | order: [], 116 | outline: [], 117 | overflow: [], 118 | padding: [], 119 | placeholderColor: [], 120 | placeholderOpacity: [], 121 | pointerEvents: [], 122 | position: [], 123 | resize: [], 124 | space: [], 125 | stroke: [], 126 | strokeWidth: [], 127 | tableLayout: [], 128 | textAlign: [], 129 | textColor: [], 130 | textOpacity: [], 131 | textDecoration: [], 132 | textTransform: [], 133 | userSelect: [], 134 | verticalAlign: [], 135 | visibility: [], 136 | whitespace: [], 137 | width: [], 138 | wordBreak: [], 139 | zIndex: [], 140 | gap: [], 141 | gridAutoFlow: [], 142 | gridTemplateColumns: [], 143 | gridColumn: [], 144 | gridColumnStart: [], 145 | gridColumnEnd: [], 146 | gridTemplateRows: [], 147 | gridRow: [], 148 | gridRowStart: [], 149 | gridRowEnd: [], 150 | transform: [], 151 | transformOrigin: [], 152 | scale: [], 153 | rotate: [], 154 | translate: [], 155 | skew: [], 156 | transitionProperty: [], 157 | transitionTimingFunction: [], 158 | transitionDuration: [], 159 | transitionDelay: [], 160 | }, 161 | corePlugins: false, 162 | plugins: [], 163 | }; 164 | -------------------------------------------------------------------------------- /plugin/src/__tests__/plugin.test.ts: -------------------------------------------------------------------------------- 1 | test('simple transform', () => { 2 | // const tailwindConfig = createConfig({}); 3 | // expect(tailwindConfig).toMatchSnapshot(); 4 | expect(true).toBe(true); 5 | }); 6 | 7 | import postcss from 'postcss'; 8 | import tailwindcss from 'tailwindcss'; 9 | 10 | import { merge } from '../utils'; 11 | import compositor from '../theme-compositor'; 12 | 13 | import compositorBaseConfig from './fixtures/compositor.config.js'; 14 | import tailwindConfig from './fixtures/tailwind.config.js'; 15 | 16 | const createPostCSSConfig = ({ config, input = '@tailwind utilities;' }) => { 17 | // make config 18 | const compositorConfig = merge(compositorBaseConfig, config); 19 | 20 | // transform tailwind theme 21 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 22 | 23 | // run postcss 24 | return postcss([tailwindcss(tailwindConfigComposed)]) 25 | .process(input, { 26 | from: undefined, 27 | }) 28 | .then(({ css }) => { 29 | return css; 30 | }); 31 | }; 32 | 33 | test('use rem', () => { 34 | const config = { 35 | options: { 36 | useRem: true, 37 | }, 38 | }; 39 | return createPostCSSConfig({ config: config }).then(css => { 40 | expect(css).toMatchSnapshot(); 41 | }); 42 | }); 43 | 44 | test('use px', () => { 45 | const config = { 46 | options: { 47 | useRem: false, 48 | }, 49 | }; 50 | return createPostCSSConfig({ config: config }).then(css => { 51 | expect(css).toMatchSnapshot(); 52 | }); 53 | }); 54 | 55 | test('baseline styles', () => { 56 | const config = { 57 | options: { 58 | useRem: false, 59 | snap: true, 60 | type: true, 61 | rhythm: false, 62 | measure: false, 63 | matrix: false, 64 | xray: false, 65 | }, 66 | }; 67 | return createPostCSSConfig({ config: config }).then(css => { 68 | expect(css).toMatchSnapshot(); 69 | }); 70 | }); 71 | 72 | test('capheight styles', () => { 73 | const config = { 74 | options: { 75 | useRem: false, 76 | snap: false, 77 | type: true, 78 | rhythm: false, 79 | measure: false, 80 | matrix: false, 81 | xray: false, 82 | }, 83 | }; 84 | return createPostCSSConfig({ config: config }).then(css => { 85 | expect(css).toMatchSnapshot(); 86 | }); 87 | }); 88 | 89 | test('rhythm styles', () => { 90 | const config = { 91 | options: { 92 | useRem: false, 93 | snap: false, 94 | type: false, 95 | rhythm: true, 96 | measure: false, 97 | matrix: false, 98 | xray: false, 99 | }, 100 | }; 101 | return createPostCSSConfig({ config: config }).then(css => { 102 | expect(css).toMatchSnapshot(); 103 | }); 104 | }); 105 | 106 | test('measure styles', () => { 107 | const config = { 108 | options: { 109 | useRem: false, 110 | snap: false, 111 | type: false, 112 | rhythm: false, 113 | measure: true, 114 | matrix: false, 115 | xray: false, 116 | }, 117 | }; 118 | return createPostCSSConfig({ config: config }).then(css => { 119 | expect(css).toMatchSnapshot(); 120 | }); 121 | }); 122 | 123 | test('matrix styles', () => { 124 | const config = { 125 | options: { 126 | useRem: false, 127 | snap: false, 128 | type: false, 129 | rhythm: false, 130 | measure: false, 131 | matrix: true, 132 | xray: false, 133 | }, 134 | }; 135 | return createPostCSSConfig({ config: config }).then(css => { 136 | expect(css).toMatchSnapshot(); 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /plugin/src/__tests__/transform.test.ts: -------------------------------------------------------------------------------- 1 | import { ICompositorConfig } from '../types'; 2 | import path from 'path'; 3 | import { merge } from '../utils'; 4 | import compositor from '../theme-compositor'; 5 | 6 | import compositorBaseConfig from './fixtures/compositor.config.js'; 7 | import tailwindConfig from './fixtures/tailwind.config.js'; 8 | 9 | const createConfig = config => { 10 | const compositorConfig: ICompositorConfig = merge( 11 | compositorBaseConfig, 12 | config 13 | ); 14 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 15 | return tailwindConfigComposed; 16 | }; 17 | 18 | test('simple transform', () => { 19 | // const tailwindConfig = createConfig({}); 20 | // expect(tailwindConfig).toMatchSnapshot(); 21 | expect(true).toBe(true); 22 | }); 23 | -------------------------------------------------------------------------------- /plugin/src/create-background-styles.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme, ICompositorConfig } from './types'; 2 | 3 | import { get } from './utils/get'; 4 | import { bgBaselineRel, bgBaseline } from './styles/style-background'; 5 | 6 | export const createBackgroundStyles = ({ 7 | theme, 8 | e, 9 | addUtilities, 10 | }: { 11 | theme: iTailwindTheme; 12 | e: any; 13 | addUtilities: Function; 14 | }) => { 15 | const { options, root, baseline, styles }: ICompositorConfig = theme( 16 | 'compositor' 17 | ); 18 | 19 | const rulerColor = get(styles, 'ruler.color', '#ff00cc'); 20 | 21 | if (!options.xray) return; 22 | 23 | const baselineBgStyles = { 24 | [`.bg-baseline`]: options.useRem 25 | ? bgBaselineRel({ baseline, root: root, color: rulerColor }) 26 | : bgBaseline({ baseline, color: rulerColor }), 27 | }; 28 | 29 | addUtilities(baselineBgStyles, []); 30 | }; 31 | 32 | export default createBackgroundStyles; 33 | -------------------------------------------------------------------------------- /plugin/src/create-matrix-styles.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme, ICompositorConfig } from './types'; 2 | import { 3 | matrixColumns, 4 | matrixGap, 5 | matrixGapX, 6 | matrixGapY, 7 | matrixCellStartX, 8 | matrixCellSpanX, 9 | matrixCellStartY, 10 | matrixCellSpanY, 11 | matrixRows, 12 | } from './styles'; 13 | 14 | /** 15 | * 16 | * 17 | */ 18 | export const createMatrixStyles = ({ 19 | theme, 20 | e, 21 | addUtilities, 22 | }: { 23 | theme: iTailwindTheme; 24 | e: any; 25 | addUtilities: Function; 26 | }) => { 27 | const { matrix, options }: ICompositorConfig = theme('compositor'); 28 | 29 | if (!options.matrix) return; 30 | 31 | const columnsScale = Array.from(new Array(matrix + 1), (v, i) => i); 32 | 33 | const rhythmScale: Array = theme('spacing'); 34 | 35 | const matrixColumnsStyles = columnsScale.map(columnIndex => { 36 | const columns = columnIndex === 0 ? 1 : columnIndex; 37 | 38 | return { 39 | [`.${e(`matrix-${columnIndex}`)}`]: matrixColumns({ 40 | columns, 41 | }), 42 | }; 43 | }); 44 | 45 | const matrixCellStyles = columnsScale.map(columnIndex => { 46 | const column = columnIndex === 0 ? 1 : columnIndex; 47 | 48 | return { 49 | [`.${e(`cell-start-x-${column}`)}`]: matrixCellStartX({ 50 | start: column, 51 | }), 52 | [`.${e(`cell-span-x-${column}`)}`]: matrixCellSpanX({ 53 | span: column, 54 | }), 55 | [`.${e(`cell-start-y-${column}`)}`]: matrixCellStartY({ 56 | start: column, 57 | }), 58 | [`.${e(`cell-span-y-${column}`)}`]: matrixCellSpanY({ 59 | span: column, 60 | }), 61 | }; 62 | }); 63 | 64 | const matrixGapStyles = Object.keys(rhythmScale).map(key => { 65 | const rhythm = rhythmScale[key]; 66 | return { 67 | [`.${e(`matrix-row-h-${key}`)}`]: matrixRows({ 68 | size: rhythm, 69 | }), 70 | [`.${e(`matrix-gap-${key}`)}`]: matrixGap({ rhythm }), 71 | [`.${e(`matrix-gap-x-${key}`)}`]: matrixGapX({ rhythm }), 72 | [`.${e(`matrix-gap-y-${key}`)}`]: matrixGapY({ rhythm }), 73 | }; 74 | }); 75 | 76 | addUtilities(matrixColumnsStyles, ['responsive']); 77 | addUtilities(matrixGapStyles, ['responsive']); 78 | addUtilities(matrixCellStyles, ['responsive']); 79 | }; 80 | 81 | export default createMatrixStyles; 82 | -------------------------------------------------------------------------------- /plugin/src/create-measure-styles.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme, ICompositorConfig } from './types'; 2 | import { measure } from './styles/style-measure'; 3 | 4 | const createMeasureStyles = ({ 5 | theme, 6 | e, 7 | addUtilities, 8 | }: { 9 | theme: iTailwindTheme; 10 | e: any; 11 | addUtilities: Function; 12 | }) => { 13 | const { measure: measureScale, options }: ICompositorConfig = theme( 14 | 'compositor' 15 | ); 16 | 17 | if (!options.measure) return; 18 | 19 | const measureStyles = Object.keys(measureScale).map(key => { 20 | const space = measureScale[key]; 21 | return { 22 | [`.${e(`measure-${key}`)}`]: measure({ space }), 23 | }; 24 | }); 25 | 26 | addUtilities(measureStyles, ['responsive']); 27 | }; 28 | 29 | export default createMeasureStyles; 30 | -------------------------------------------------------------------------------- /plugin/src/create-rhythm-styles.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme, ICompositorConfig } from './types'; 2 | import { owlX, owlY } from './styles'; 3 | 4 | /** 5 | * 6 | * 7 | */ 8 | export const createRhythmStyles = ({ 9 | theme, 10 | e, 11 | addUtilities, 12 | }: { 13 | theme: iTailwindTheme; 14 | e: any; 15 | addUtilities: Function; 16 | }) => { 17 | const { options }: ICompositorConfig = theme('compositor'); 18 | 19 | if (!options.rhythm) return; 20 | 21 | const rhythmScale: Array = theme('spacing'); 22 | 23 | const rhythmStyles = Object.keys(rhythmScale).map(key => { 24 | const space: string = rhythmScale[key]; 25 | return { 26 | [`.${e(`rhythm-${key}`)}`]: owlY({ space }), 27 | [`.${e(`rhythm-y-${key}`)}`]: owlY({ space }), 28 | [`.${e(`rhythm-x-${key}`)}`]: owlX({ space }), 29 | }; 30 | }); 31 | 32 | addUtilities(rhythmStyles, ['responsive']); 33 | }; 34 | 35 | export default createRhythmStyles; 36 | -------------------------------------------------------------------------------- /plugin/src/create-text-styles.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme, ICompositorConfig, iFontOpenType } from './types'; 2 | var flattenDeep = require('lodash.flattendeep'); 3 | 4 | import { styleFontFamily, styleText } from './styles'; 5 | 6 | /** 7 | * 8 | * 9 | */ 10 | export const createTextStyles = ({ 11 | theme, 12 | e, 13 | addUtilities, 14 | }: { 15 | theme: iTailwindTheme; 16 | e: any; 17 | addUtilities: Function; 18 | }) => { 19 | const { 20 | root, 21 | baseline, 22 | leading, 23 | fonts, 24 | type, 25 | options, 26 | }: ICompositorConfig = theme('compositor'); 27 | 28 | const familyStyles = fonts.map((font: iFontOpenType) => { 29 | return { 30 | [`.font-${font.key}`]: styleFontFamily({ font }), 31 | }; 32 | }); 33 | 34 | const leadingScale = Array.from(new Array(leading + 1), (v, i) => i); 35 | 36 | const sizeStyles = flattenDeep( 37 | fonts.map((font: iFontOpenType) => 38 | type.map((size, sizeIdx) => { 39 | return leadingScale.map(lead => { 40 | // 41 | // create baseline styles 42 | const outputTextStyle = styleText({ 43 | font: font, 44 | root: root, 45 | baseline: baseline, 46 | size: size, 47 | leading: lead, 48 | snap: options.snap, 49 | useRem: options.useRem, 50 | }); 51 | 52 | // apply if variant type is enabled 53 | const textStyles = { 54 | [`&.${e(`text-${sizeIdx}/${lead}`)}`]: outputTextStyle, 55 | }; 56 | 57 | return { 58 | [`.font-${font.key}`]: { 59 | ...textStyles, 60 | }, 61 | }; 62 | }); 63 | }) 64 | ) 65 | ); 66 | addUtilities(familyStyles, []); 67 | addUtilities(sizeStyles, ['responsive']); 68 | }; 69 | 70 | export default createTextStyles; 71 | -------------------------------------------------------------------------------- /plugin/src/default-config.ts: -------------------------------------------------------------------------------- 1 | import { ICompositorConfig } from './types'; 2 | 3 | // baseline grid row height in px 4 | export const root = 16; 5 | 6 | // baseline grid row height in px 7 | export const baseline = 8; 8 | 9 | // max leading count 10 | export const leading = 4; 11 | 12 | // matrix columns 13 | export const matrix = 12; 14 | 15 | // type scale in px 16 | export const type = [ 17 | 12, 18 | 14, 19 | 16, 20 | 18, 21 | 20, 22 | 24, 23 | 28, 24 | 32, 25 | 36, 26 | 42, 27 | 48, 28 | 54, 29 | 60, 30 | 68, 31 | 76, 32 | 84, 33 | 92, 34 | ]; 35 | 36 | // rhythm scale in baseline units 37 | export const rhythm = [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14]; 38 | 39 | // measure scale in characters unit 40 | export const measure = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65]; 41 | 42 | // font config 43 | export const fonts = [ 44 | { 45 | key: 'sans-400', 46 | fallback: 'sans-serif', 47 | familyName: 'Inter', 48 | upm: 2816, 49 | xHeight: 1536, 50 | capHeight: 2048, 51 | ascent: 2728, 52 | descent: -680, 53 | weight: 400, 54 | italic: false, 55 | }, 56 | { 57 | key: 'sans-400i', 58 | fallback: 'sans-serif', 59 | familyName: 'Inter', 60 | upm: 2816, 61 | xHeight: 1536, 62 | capHeight: 2048, 63 | ascent: 2728, 64 | descent: -680, 65 | weight: 400, 66 | italic: true, 67 | }, 68 | { 69 | key: 'sans-600', 70 | fallback: 'sans-serif', 71 | familyName: 'Inter', 72 | upm: 2816, 73 | xHeight: 1536, 74 | capHeight: 2048, 75 | ascent: 2728, 76 | descent: -680, 77 | weight: 600, 78 | italic: false, 79 | }, 80 | { 81 | key: 'sans-600i', 82 | fallback: 'sans-serif', 83 | familyName: 'Inter', 84 | upm: 2816, 85 | xHeight: 1536, 86 | capHeight: 2048, 87 | ascent: 2728, 88 | descent: -680, 89 | weight: 600, 90 | italic: true, 91 | }, 92 | ]; 93 | 94 | export const options = { 95 | snap: true, 96 | useRem: true, 97 | type: true, 98 | rhythm: true, 99 | measure: true, 100 | matrix: true, 101 | xray: true, 102 | }; 103 | -------------------------------------------------------------------------------- /plugin/src/get-font-metrics.ts: -------------------------------------------------------------------------------- 1 | import fontkit from 'fontkit'; 2 | 3 | import get from './utils/get'; 4 | 5 | type FontKitMetrics = { 6 | familyName: string; 7 | upm: number; 8 | xHeight: number; 9 | capHeight: number; 10 | lineGap: number; 11 | ascent: number; 12 | descent: number; 13 | weight: number; 14 | italic: boolean; 15 | }; 16 | 17 | export const getFontMetrics = (file: string): FontKitMetrics => { 18 | const font = fontkit.openSync(file); 19 | 20 | const weight = font['OS/2'].usWeightClass; 21 | const italic = font['OS/2'].fsSelection.italic; 22 | 23 | return { 24 | familyName: font.familyName, 25 | upm: font.unitsPerEm, 26 | xHeight: font.xHeight, 27 | capHeight: font.capHeight, 28 | lineGap: font.lineGap, 29 | ascent: font.ascent, 30 | descent: font.descent, 31 | weight: weight, 32 | italic: italic, 33 | }; 34 | }; 35 | 36 | export default getFontMetrics; 37 | -------------------------------------------------------------------------------- /plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tailwind-plugin-compositor'; 2 | export * from './theme-compositor'; 3 | -------------------------------------------------------------------------------- /plugin/src/styles/index.ts: -------------------------------------------------------------------------------- 1 | export * from './style-background'; 2 | 3 | export * from './style-text'; 4 | export * from './style-font-family'; 5 | export * from './style-matrix'; 6 | export * from './style-measure'; 7 | export * from './style-owl'; 8 | 9 | -------------------------------------------------------------------------------- /plugin/src/styles/style-background.ts: -------------------------------------------------------------------------------- 1 | export const bgBaselineRel = ({ 2 | baseline, 3 | root, 4 | color, 5 | }: { 6 | baseline: number; 7 | root: number; 8 | color?: string; 9 | }) => ({ 10 | position: 'relative', 11 | backgroundRepeat: 'repeat', 12 | backgroundSize: `100% ${baseline / root}rem`, 13 | backgroundImage: `linear-gradient( 14 | ${color} 1px, 15 | transparent 0 16 | )`, 17 | }); 18 | 19 | export const bgBaseline = ({ 20 | baseline, 21 | color, 22 | }: { 23 | baseline: number; 24 | color: string; 25 | }) => ({ 26 | position: 'relative', 27 | backgroundRepeat: 'repeat', 28 | backgroundImage: `linear-gradient( 29 | ${color} 1px, 30 | transparent 0 31 | )`, 32 | backgroundSize: `100% ${baseline}px`, 33 | }); 34 | -------------------------------------------------------------------------------- /plugin/src/styles/style-font-family.ts: -------------------------------------------------------------------------------- 1 | import { TypeFamilyParams, StyleFamily } from '../types'; 2 | 3 | /** 4 | * 5 | * 6 | */ 7 | export const styleFontFamily = (params: TypeFamilyParams): StyleFamily => { 8 | // 9 | const { font } = params; 10 | 11 | return { 12 | fontFamily: `"${font.familyName}", ${font.fallback}`, 13 | fontWeight: font.weight, 14 | fontStyle: font.italic ? 'italic' : 'normal', 15 | display: 'block', 16 | ['&::before, &::after']: { 17 | content: `''`, 18 | display: 'block', 19 | height: 0, 20 | }, 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /plugin/src/styles/style-matrix.ts: -------------------------------------------------------------------------------- 1 | import { Style } from '../types'; 2 | 3 | export const matrixColumns = ({ columns }: { columns: number }): Style => { 4 | const result: Style = { 5 | display: 'grid', 6 | gridTemplateColumns: `repeat(${columns}, minmax(auto,1fr))`, 7 | }; 8 | 9 | return result; 10 | }; 11 | 12 | export const matrixRows = ({ size }: { size?: string }): Style => { 13 | const result: Style = { 14 | gridAutoRows: `minmax(${size}, auto)`, 15 | }; 16 | 17 | return result; 18 | }; 19 | 20 | export const matrixCellStartX = ({ start }: { start: number }): Style => { 21 | const result: Style = { 22 | gridColumnStart: `${start} !important`, 23 | }; 24 | 25 | return result; 26 | }; 27 | 28 | export const matrixCellSpanX = ({ span }: { span: number }): Style => { 29 | const result: Style = { 30 | gridColumn: `auto / span ${span}`, 31 | }; 32 | 33 | return result; 34 | }; 35 | 36 | export const matrixCellStartY = ({ start }: { start: number }): Style => { 37 | const result: Style = { 38 | gridRowStart: `${start} !important`, 39 | }; 40 | 41 | return result; 42 | }; 43 | 44 | export const matrixCellSpanY = ({ span }: { span: number }): Style => { 45 | const result: Style = { 46 | gridRow: `auto / span ${span}`, 47 | }; 48 | 49 | return result; 50 | }; 51 | 52 | export const matrixGap = ({ rhythm }: { rhythm: string }): Style => { 53 | return { 54 | gridRowGap: rhythm, 55 | gridColumnGap: rhythm, 56 | }; 57 | }; 58 | 59 | export const matrixGapX = ({ rhythm }: { rhythm: string }): Style => { 60 | return { 61 | gridColumnGap: rhythm, 62 | }; 63 | }; 64 | 65 | export const matrixGapY = ({ rhythm }: { rhythm: string }): Style => { 66 | return { 67 | gridRowGap: rhythm, 68 | }; 69 | }; 70 | -------------------------------------------------------------------------------- /plugin/src/styles/style-measure.ts: -------------------------------------------------------------------------------- 1 | import { Style } from '../types'; 2 | 3 | export const measure = ({ space }: { space: string }): Style => { 4 | return { 5 | maxWidth: `${space}`, 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /plugin/src/styles/style-owl.ts: -------------------------------------------------------------------------------- 1 | import { Style } from '../types'; 2 | 3 | export const owlY = ({ space }: { space: string }): Style => { 4 | return { 5 | [`& > * + * `]: { 6 | marginTop: space, 7 | }, 8 | }; 9 | }; 10 | 11 | export const owlX = ({ space }: { space: string }): Style => { 12 | return { 13 | [`& > * + * `]: { 14 | marginLeft: space, 15 | }, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /plugin/src/styles/style-text.ts: -------------------------------------------------------------------------------- 1 | import { StyleTypography, TypeStyleParams } from '../types'; 2 | 3 | /** 4 | * 5 | * 6 | */ 7 | export const styleText = ({ 8 | font, 9 | baseline, 10 | size, 11 | leading = 0, 12 | snap = false, 13 | root = null, 14 | useRem = false, 15 | }: TypeStyleParams): StyleTypography => { 16 | // ratios 17 | const preventCollapse = 0.4; 18 | const descentAbs = Math.abs(font.descent); 19 | const capHeightRatio = font.capHeight / font.upm; 20 | const xHeightRatio = font.xHeight / font.upm; 21 | const ascentRatio = (font.ascent - font.capHeight) / font.upm; 22 | const descentRatio = descentAbs / font.upm; 23 | 24 | // bounding box 25 | const boundingBox = font.ascent + descentAbs + font.lineGap; 26 | const boundingBoxHeight = (boundingBox / font.upm) * size; 27 | 28 | // type height 29 | const capSize = capHeightRatio * size; 30 | const baselineRows = capSize / baseline; 31 | const typeRows = Math.round(baselineRows); 32 | // const typeRows = capSize / baseline % 1 < 0.8 ? Math.floor(baselineRows) : Math.ceil(baselineRows); 33 | const typeHeight = snap ? typeRows * baseline : capSize; 34 | 35 | // leading 36 | const leadingValue = snap ? Math.round(leading) : leading; 37 | const minLeading = snap ? typeRows : typeHeight; 38 | const typeLeading = 39 | leading < 0 ? Math.max(leadingValue, minLeading * -1) : leadingValue; 40 | 41 | // line height 42 | const typeLineGap = typeLeading * baseline; 43 | const typeLineHeight = typeHeight + typeLineGap; 44 | 45 | // leading trim 46 | const lineGapHeight = (font.lineGap / font.upm) * size; 47 | const lineHeightOffset = 48 | (boundingBoxHeight - typeLineHeight - lineGapHeight) / 2; 49 | 50 | const trimTop = ascentRatio * size - lineHeightOffset; 51 | const trimBottom = descentRatio * size - lineHeightOffset; 52 | 53 | // align to baseline 54 | const paddingTop = snap 55 | ? preventCollapse + ((trimBottom + trimTop) % baseline) 56 | : preventCollapse; 57 | 58 | const trimTopSize = trimTop * -1 - preventCollapse; 59 | const trimBottomSize = trimBottom * -1 - preventCollapse; 60 | 61 | const trimTopValue = useRem 62 | ? `${trimTopSize / size}em` 63 | : `${trimTopSize}px`; 64 | 65 | const trimBottomValue = useRem 66 | ? `${trimBottomSize / size}em` 67 | : `${trimBottomSize}px`; 68 | 69 | const fontSizeValue = useRem ? `${size / root}rem` : `${size}px`; 70 | 71 | const lineHeightValue = useRem 72 | ? `${typeLineHeight / size}` 73 | : `${typeLineHeight}px`; 74 | 75 | const paddingTopValue = useRem 76 | ? `${paddingTop / size}em` 77 | : `${paddingTop}px`; 78 | 79 | const paddingBottomValue = useRem 80 | ? `${preventCollapse / size}em` 81 | : `${preventCollapse}px`; 82 | 83 | return { 84 | fontSize: fontSizeValue, 85 | lineHeight: lineHeightValue, 86 | paddingTop: paddingTopValue, 87 | paddingBottom: paddingBottomValue, 88 | ['&::before']: { 89 | marginTop: trimTopValue, 90 | }, 91 | ['&::after']: { 92 | marginBottom: trimBottomValue, 93 | }, 94 | }; 95 | }; 96 | -------------------------------------------------------------------------------- /plugin/src/tailwind-plugin-compositor.ts: -------------------------------------------------------------------------------- 1 | import { iTailwindTheme } from './types'; 2 | 3 | import createTextStyles from './create-text-styles'; 4 | import createBackgroundStyles from './create-background-styles'; 5 | import createMeasureStyles from './create-measure-styles'; 6 | import createRhythmStyles from './create-rhythm-styles'; 7 | import createMatrixStyles from './create-matrix-styles'; 8 | 9 | export const tailwindPluginCompositor = () => { 10 | return ({ 11 | theme, 12 | e, 13 | addUtilities, 14 | }: { 15 | theme: iTailwindTheme; 16 | e: any; 17 | addUtilities: Function; 18 | }) => { 19 | createTextStyles({ theme, e, addUtilities }); 20 | createBackgroundStyles({ theme, e, addUtilities }); 21 | createMeasureStyles({ theme, e, addUtilities }); 22 | createRhythmStyles({ theme, e, addUtilities }); 23 | createMatrixStyles({ theme, e, addUtilities }); 24 | }; 25 | }; 26 | 27 | export default tailwindPluginCompositor; 28 | -------------------------------------------------------------------------------- /plugin/src/theme-compositor.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { 3 | ICompositorConfig, 4 | iTailwindConfig, 5 | iFontOpenType, 6 | UtilityOptions, 7 | FontsConfig, 8 | } from './types'; 9 | 10 | import getFontMetrics from './get-font-metrics'; 11 | import tailwindPluginCompositor from './tailwind-plugin-compositor'; 12 | 13 | import is from './utils/is'; 14 | import merge from './utils/merge'; 15 | import baselineScaleToRem from './utils/baseline-scale-to-rem'; 16 | import baselineScaleToPx from './utils/baseline-scale-to-px'; 17 | import pxScaleToRem from './utils/px-scale-to-rem'; 18 | import scaleAddSuffix from './utils/scale-add-suffix'; 19 | 20 | const cacheFileName = '.compositor'; 21 | 22 | import { 23 | root as defaultRoot, 24 | matrix as defaultMatrix, 25 | type as defaultType, 26 | rhythm as defaultRhythm, 27 | measure as defaultMeasure, 28 | leading as defaultLeading, 29 | baseline as defaultBaseline, 30 | options as defaultOptions, 31 | fonts as defaultFonts, 32 | } from './default-config'; 33 | 34 | type TwTheme = { 35 | extend: any; 36 | }; 37 | 38 | const defaultStyles = { 39 | ruler: { 40 | color: 'rgba(255, 0, 255, 0.3)', 41 | }, 42 | }; 43 | 44 | export const compositor = (compositorConfig: ICompositorConfig) => ( 45 | tailwindConfig: iTailwindConfig 46 | ): iTailwindConfig => { 47 | let fontsConfig: Array = []; 48 | let fontsCached = false; 49 | 50 | // try { 51 | // if (fs.existsSync(cacheFileName)) { 52 | // const rawCache: any = fs.readFileSync(cacheFileName); 53 | // fontsConfig = JSON.parse(rawCache); 54 | // fontsCached = true; 55 | // } 56 | // } catch (err) { 57 | // console.error(err); 58 | // } 59 | 60 | // first get some tailwind 61 | // tailwind config values 62 | const { 63 | theme = {} as TwTheme, 64 | plugins = [], 65 | ...tailwindRest 66 | } = tailwindConfig; 67 | 68 | // extend is nested under theme 69 | const { extend = {} } = theme; 70 | 71 | // get necessary params from compositor 72 | // we only need type and rhythm 73 | // to transform to px or rem usings 74 | // based on useRem, root and baseline params 75 | const { 76 | root = defaultRoot, 77 | baseline = defaultBaseline, 78 | fonts = defaultFonts as FontsConfig, 79 | type = defaultType, 80 | rhythm = defaultRhythm, 81 | measure = defaultMeasure, 82 | options: configOptions, 83 | } = compositorConfig; 84 | // 85 | 86 | const options: UtilityOptions = merge(defaultOptions, configOptions); 87 | 88 | if (options.useRem && !is.exists(root)) { 89 | throw 'With options.useRem:true, root is required'; 90 | } 91 | 92 | if (!fontsCached) { 93 | fontsConfig = []; 94 | fonts.forEach(({ file, ...fontRest }) => { 95 | let fontOT: iFontOpenType; 96 | if (is.string(file) && is.exists(file)) { 97 | fontOT = merge(getFontMetrics(file), { ...fontRest }); 98 | } else { 99 | fontOT = { ...fontRest } as iFontOpenType; 100 | } 101 | 102 | fontsConfig.push(fontOT); 103 | }); 104 | 105 | fs.writeFileSync(cacheFileName, JSON.stringify(fontsConfig)); 106 | } 107 | 108 | // [16,22,30,42,56] 109 | // type scale is described in px units 110 | // so transform to rem or px 111 | // depending on useRem 112 | const typeScale = options.useRem ? pxScaleToRem(root)(type) : type; 113 | 114 | // [1,2,3,4,5] 115 | // rhythm scale is described in baseline units 116 | // transform to tailwind format 117 | // rem or px depending on useRem param 118 | const spacingScale = options.useRem 119 | ? baselineScaleToRem(baseline)(root)(rhythm) 120 | : baselineScaleToPx(baseline)(rhythm); 121 | 122 | // 123 | // measure scale is described in ch units 124 | // transform to tailwind format 125 | // string or ch 126 | const measureScale = scaleAddSuffix('ch')(measure); 127 | 128 | // deconstruct tailwind extend 129 | // and get height, minHeight, maxHeight scales 130 | // to merge with the spacingScale 131 | // don't extend spacing, 132 | const { 133 | height = {}, 134 | minHeight = {}, 135 | maxHeight = {}, 136 | fontSize = {}, 137 | ...extendRest 138 | } = extend; 139 | 140 | // 141 | const out = { 142 | ...tailwindRest, 143 | theme: { 144 | ...theme, 145 | fontSize: typeScale, // overwrite type scale 146 | spacing: spacingScale, // overwrite spacing scale 147 | // compositor params via theme 148 | // rather than plugin below 149 | compositor: { 150 | ...compositorConfig, 151 | styles: defaultStyles, 152 | measure: measureScale, 153 | fonts: fontsConfig, 154 | }, 155 | extend: { 156 | ...extendRest, 157 | height: merge(height, spacingScale), 158 | minHeight: merge(minHeight, spacingScale), 159 | maxHeight: merge(maxHeight, spacingScale), 160 | }, 161 | }, 162 | plugins: [...plugins, tailwindPluginCompositor()], 163 | }; 164 | 165 | return out; 166 | }; 167 | 168 | export default compositor; 169 | -------------------------------------------------------------------------------- /plugin/src/types.ts: -------------------------------------------------------------------------------- 1 | import * as CSS from 'csstype'; 2 | 3 | // type TLengthStyledSystem = string | 0 | number; 4 | 5 | // type ObjectOrArray = T[] | { [K: string]: T | ObjectOrArray }; 6 | 7 | export type NumberScale = Array; 8 | 9 | export type FontConfigCache = Array; 10 | 11 | export type iTailwindTheme = Function; 12 | 13 | export type iTailwindConfig = { 14 | theme: { 15 | extend: any; 16 | [key: string]: any; 17 | }; 18 | variants: any; 19 | corePlugins: any; 20 | plugins: any; 21 | compositor: ICompositorConfig; 22 | }; 23 | 24 | export interface iFontOpenType { 25 | key: string; 26 | file?: string; 27 | fallback: string; 28 | familyName: string; 29 | upm: number; 30 | xHeight: number; 31 | capHeight: number; 32 | lineGap: number; 33 | ascent: number; 34 | descent: number; 35 | weight: number; 36 | italic: boolean; 37 | } 38 | 39 | export type FontConfigFile = { 40 | file: string; 41 | key: string; 42 | familyName: string; 43 | fallback: string; 44 | weight?: number; 45 | italic?: boolean; 46 | upm: undefined; 47 | xHeight: undefined; 48 | capHeight: undefined; 49 | ascent: undefined; 50 | descent: undefined; 51 | }; 52 | 53 | export type FontsConfig = Array; 54 | 55 | export interface UtilityOptions { 56 | useRem: boolean; 57 | snap: boolean; 58 | type: boolean; 59 | rhythm: boolean; 60 | measure: boolean; 61 | matrix: boolean; 62 | xray: boolean; 63 | } 64 | 65 | export interface ICompositorConfig { 66 | root: number; 67 | baseline: number; 68 | leading: number; 69 | matrix: number; 70 | type: NumberScale; 71 | measure: NumberScale; 72 | rhythm: NumberScale; 73 | fonts: FontsConfig; 74 | options: UtilityOptions; 75 | styles: iCompositorThemeStyles; 76 | } 77 | 78 | export interface iCompositorThemeStyles { 79 | ruler: { 80 | color: string; 81 | }; 82 | } 83 | 84 | export interface Style extends CSS.Properties { 85 | [key: string]: any; 86 | } 87 | 88 | export interface TypeFamilyParams { 89 | font: iFontOpenType; 90 | } 91 | 92 | export interface StyleFamily { 93 | fontFamily: CSS.FontFamilyProperty; 94 | fontWeight: CSS.FontWeightProperty; 95 | fontStyle: CSS.FontStyleProperty; 96 | display: CSS.DisplayProperty; 97 | '&::before, &::after': { 98 | content: CSS.ContentProperty; 99 | height: CSS.HeightProperty; 100 | display: CSS.DisplayProperty; 101 | }; 102 | } 103 | 104 | export interface TypeStyleRelParams { 105 | font: iFontOpenType; 106 | baseline: number; 107 | root: number; 108 | size: number; 109 | leading: number; 110 | useRem: boolean; 111 | } 112 | 113 | export interface TypeStyleParams { 114 | font: iFontOpenType; 115 | baseline: number; 116 | size: number; 117 | snap: boolean; 118 | leading: number; 119 | root?: number; 120 | useRem: boolean; 121 | } 122 | 123 | export interface StyleTypography { 124 | fontSize: CSS.FontSizeProperty; 125 | lineHeight: CSS.LineHeightProperty; 126 | paddingTop: CSS.PaddingTopProperty; 127 | paddingBottom: CSS.PaddingTopProperty; 128 | '&::before': { 129 | marginTop: CSS.MarginProperty; 130 | }; 131 | '&::after': { 132 | marginBottom: CSS.MarginProperty; 133 | }; 134 | } 135 | -------------------------------------------------------------------------------- /plugin/src/utils/baseline-scale-to-px.ts: -------------------------------------------------------------------------------- 1 | import { is } from './is'; 2 | 3 | export const baselineScaleToPx = baseline => scale => { 4 | const result = Object.keys(scale).reduce((res, key) => { 5 | const value = scale[key]; 6 | return { 7 | [key]: is.num(value) ? `${value * baseline}px` : value, 8 | ...res, 9 | }; 10 | }, {}); 11 | return result; 12 | }; 13 | 14 | export default baselineScaleToPx; 15 | -------------------------------------------------------------------------------- /plugin/src/utils/baseline-scale-to-rem.ts: -------------------------------------------------------------------------------- 1 | import { is } from './is'; 2 | import { pxToRem } from './px-to-rem'; 3 | 4 | export const baselineScaleToRem = baseline => root => scale => { 5 | const result = Object.keys(scale).reduce((res, key) => { 6 | const toRootEm = pxToRem(root); 7 | const value = scale[key]; 8 | return { 9 | [key]: is.num(value) ? `${toRootEm(value * baseline)}rem` : value, 10 | ...res, 11 | }; 12 | }, {}); 13 | return result; 14 | }; 15 | 16 | export default baselineScaleToRem; 17 | -------------------------------------------------------------------------------- /plugin/src/utils/get-rhythm.ts: -------------------------------------------------------------------------------- 1 | import { is } from './is'; 2 | import { get } from './get'; 3 | import { pxToRem } from './px-to-rem'; 4 | 5 | // 6 | export const getRhythm = theme => key => { 7 | // 8 | const { useRem, root, baseline } = theme; 9 | const toRootEm = pxToRem(root); 10 | 11 | const valuePrevix = is.num(key) && key < 0 ? '-' : ''; 12 | const scaleKey = is.num(key) ? Math.abs(key) : key; 13 | const scaleValue = get(theme.rhythm, scaleKey, scaleKey); 14 | 15 | // if it's just a number, transform to px or rem if useRem 16 | const styleValue = is.num(scaleValue) 17 | ? is.truthy(useRem) 18 | ? `${valuePrevix}${toRootEm(scaleValue * baseline)}rem` 19 | : `${valuePrevix}${scaleValue * baseline}px` 20 | : // else try to get a theme value 21 | get(theme, key, key); 22 | 23 | return styleValue; 24 | }; 25 | 26 | export default getRhythm; 27 | -------------------------------------------------------------------------------- /plugin/src/utils/get.ts: -------------------------------------------------------------------------------- 1 | // based on https://github.com/developit/dlv 2 | export const get = (obj: any, key, def, p: number = 0, undef?) => { 3 | key = key && key.split ? key.split('.') : [key]; 4 | for (p = 0; p < key.length; p++) { 5 | obj = obj ? obj[key[p]] : undef; 6 | } 7 | return obj === undef ? def : obj; 8 | }; 9 | 10 | export default get; 11 | -------------------------------------------------------------------------------- /plugin/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './uuid'; 2 | export * from './merge'; 3 | export * from './get'; 4 | export * from './is'; 5 | export * from './mem'; 6 | export * from './noop'; 7 | export * from './strip-css'; 8 | export * from './baseline-scale-to-rem'; 9 | export * from './baseline-scale-to-px'; 10 | export * from './px-scale-to-rem'; 11 | export * from './px-to-rem'; 12 | export * from './get-rhythm'; 13 | export * from './scale-add-suffix'; 14 | -------------------------------------------------------------------------------- /plugin/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | export const is = { 2 | truthy: n => n !== undefined && n !== null && n !== false, 3 | exists: n => n !== undefined && n !== null, 4 | undefined: n => n === undefined, 5 | array: n => Array.isArray(n), 6 | num: n => typeof n === 'number' && !Number.isNaN(n), 7 | func: f => typeof f === 'function', 8 | object: n => typeof n === 'object' && n !== null, 9 | emptyObject: obj => 10 | Object.entries(obj).length === 0 && obj.constructor === Object, 11 | string: str => Object.prototype.toString.call(str) === '[object String]', 12 | cssunit: value => 13 | [ 14 | 'px', 15 | 'em', 16 | 'ex', 17 | 'ch', 18 | 'rem', 19 | 'vh', 20 | 'vw', 21 | 'vmin', 22 | 'vmax', 23 | 'inherit', 24 | ].some(u => value.includes(u)), 25 | }; 26 | 27 | export default is; 28 | -------------------------------------------------------------------------------- /plugin/src/utils/mem.ts: -------------------------------------------------------------------------------- 1 | export const mem = func => { 2 | const mem = {}; 3 | return (...params) => { 4 | const key = String(params); 5 | if (!mem[key]) { 6 | mem[key] = func(...params); 7 | } 8 | return mem[key]; 9 | }; 10 | }; 11 | 12 | export default mem; 13 | -------------------------------------------------------------------------------- /plugin/src/utils/merge.ts: -------------------------------------------------------------------------------- 1 | export const merge = (a, b) => { 2 | let result = Object.assign({}, a, b); 3 | for (const key in a) { 4 | if (!a[key] || typeof b[key] !== 'object') continue; 5 | Object.assign(result, { 6 | [key]: Object.assign(a[key], b[key]), 7 | }); 8 | } 9 | return result; 10 | }; 11 | 12 | export default merge; 13 | -------------------------------------------------------------------------------- /plugin/src/utils/noop.ts: -------------------------------------------------------------------------------- 1 | export const noop = n => n; 2 | 3 | export default noop; 4 | -------------------------------------------------------------------------------- /plugin/src/utils/px-scale-to-rem.ts: -------------------------------------------------------------------------------- 1 | import { is } from './is'; 2 | import { pxToRem } from './px-to-rem'; 3 | 4 | export const pxScaleToRem = root => scale => { 5 | // 6 | const result = Object.keys(scale).reduce((res, key) => { 7 | const toRootEm = pxToRem(root); 8 | const value = scale[key]; 9 | // 10 | return { 11 | [key]: is.num(value) ? `${toRootEm(value)}rem` : value, 12 | ...res, 13 | }; 14 | }, {}); 15 | return result; 16 | }; 17 | 18 | export default pxScaleToRem; 19 | -------------------------------------------------------------------------------- /plugin/src/utils/px-to-rem.ts: -------------------------------------------------------------------------------- 1 | export const pxToRem = (root: number) => (px: number) => px / root; 2 | 3 | export default pxToRem; 4 | -------------------------------------------------------------------------------- /plugin/src/utils/scale-add-suffix.ts: -------------------------------------------------------------------------------- 1 | import { is } from './is'; 2 | export const scaleAddSuffix = suffix => scale => { 3 | // 4 | const result = Object.keys(scale).reduce((res, key) => { 5 | const value = scale[key]; 6 | // 7 | return { 8 | [key]: is.num(value) ? `${value}${suffix}` : value, 9 | ...res, 10 | }; 11 | }, {}); 12 | return result; 13 | }; 14 | 15 | export default scaleAddSuffix; 16 | -------------------------------------------------------------------------------- /plugin/src/utils/strip-css.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/benface/jest-matcher-css/blob/master/index.js 2 | export const stripcss = function (str) { 3 | return str.replace(/[;\s]/g, ''); 4 | }; 5 | 6 | export default stripcss; 7 | -------------------------------------------------------------------------------- /plugin/src/utils/uuid.ts: -------------------------------------------------------------------------------- 1 | export const uuid = prefix => 2 | `${prefix}-${ 3 | Math.random().toString(36).substring(2) + Date.now().toString(36) 4 | }`; 5 | 6 | export default uuid; 7 | -------------------------------------------------------------------------------- /plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.settings.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "baseUrl": "./" 6 | }, 7 | "include": ["src/**/*", "jest.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /plugin/types.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tol-is/tailwind-compositor/c7e422cb8141521b6c03dcbbb3c69eb522a44128/plugin/types.d.ts -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Tailwind Compositor 2 | 3 | Compositor is a system of constraints designed to produce aesthetically pleasing, typographic compositions, based on objective, constant dimensions of space. 4 | 5 | A baseline-grid typography system for [tailwindcss](https://tailwindcss.com/). 6 | 7 | Algorithm Demo: [Styled Baseline](https://styled-baseline.netlify.app/) 8 | 9 | --- 10 | 11 | ## Installation 12 | 13 | You will need fontkit, postcss and tailwindcss installed along with the plugin 14 | 15 | ``` 16 | npm install postcss fontkit tailwindcss tailwind-compositor 17 | ``` 18 | 19 | #### - postcss.config.js 20 | 21 | In your `postcss.config.js` you will need to import your standard `tailwind.config.js`, but also your `compositor.config.js`. 22 | 23 | The `{ compositor }` will receive both, merge with your tailwind config, and return a standard tailwind configuration. 24 | 25 | ``` 26 | const tailwindcss = require('tailwindcss'); 27 | const { compositor } = require('tailwind-compositor'); 28 | 29 | // import both configurations 30 | const compositorConfig = require('./compositor.config.js'); 31 | const tailwindConfig = require('./tailwind.config.js'); 32 | 33 | // compose config 34 | const tailwindConfigComposed = compositor(compositorConfig)(tailwindConfig); 35 | 36 | // use with tailwind 37 | module.exports = { 38 | plugins: [ 39 | tailwindcss(tailwindConfigComposed), 40 | ], 41 | }; 42 | ``` 43 | 44 | --- 45 | 46 | ## Configuration 47 | 48 | #### - compositor.config.js 49 | 50 | ``` 51 | module.exports = { 52 | // root unit 53 | root: 16, 54 | 55 | // baseline grid height in px units 56 | baseline: 8, 57 | 58 | // maximum leading 59 | leading: 4, 60 | 61 | // matrix max columns 62 | matrix: 4, 63 | 64 | // type scale in px units 65 | type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56, 60, 72], 66 | 67 | // spacing scale in baseline units 68 | rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12], 69 | 70 | // line width in ch units 71 | measure: [10, 15, 20, 30, 35, 50, 55, 60, 65], 72 | 73 | // webfonts and vertical metrics 74 | fonts: [ 75 | { 76 | key: "sans-400", 77 | familyName: "Inter", 78 | fallback: "sans-serif", 79 | weight: 400, 80 | italic: false, 81 | upm: 2816, 82 | xHeight: 1536, 83 | capHeight: 2048, 84 | ascent: 2728, 85 | descent: -680 86 | }, 87 | { 88 | key: 'sans-600', 89 | familyName: "Inter", 90 | fallback: 'sans-serif', 91 | file: path.resolve('./fonts/inter/Inter-Semibold.woff2'), 92 | }, 93 | ], 94 | 95 | // compositor options 96 | options: { 97 | useRem: true, 98 | snap: true, 99 | type: true, 100 | rhythm: true, 101 | measure: true, 102 | matrix: true, 103 | xray: true, 104 | }, 105 | } 106 | ``` 107 | 108 | --- 109 | 110 | #### 1/9 - root: integer 111 | 112 | The root font size, in `px` units. 113 | 114 | --- 115 | 116 | #### 2/9 - baseline: integer 117 | 118 | The baseline grid row height, in `px` units. 119 | 120 | --- 121 | 122 | #### 3/9 - leading: integer 123 | 124 | The maximum leading value in baseline units. 125 | 126 | --- 127 | 128 | #### 4/9 - matrix: integer 129 | 130 | The maximum columns on the matrix utility 131 | 132 | --- 133 | 134 | #### 5/9 - type : array[integer] 135 | 136 | ``` 137 | type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56, 60, 72] 138 | ``` 139 | 140 | The system's typographic scale, in `px` units. 141 | 142 | --- 143 | 144 | #### 6/9 - rhythm : array[integer] 145 | 146 | ``` 147 | rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12] 148 | ``` 149 | 150 | The system's size and spacing scale, in `baseline` units, used for `rhythm`, `margin`, `padding`, `width/min/max`, `height/min/max` and `grid-gap` utilities 151 | 152 | --- 153 | 154 | #### 7/9 - measure : array[integer] 155 | 156 | ``` 157 | measure: [10, 15, 20, 30, 35, 50, 55, 60, 65] 158 | ``` 159 | 160 | Separate scale used for `measure` (line-width) utilities, configured in `ch` units. 161 | 162 | --- 163 | 164 | #### 8/9 - fonts : array[opentype] 165 | 166 | The font scale provides all the information needed to render text styles. Each entry describes a font/weight/style set, and only those that are part of the system will be enabled. 167 | 168 | The `file` property, is used to extract the vertical metrics dynamically from the font-file. If you want to configure the metrics manually, you can omit the `file` prop. 169 | 170 | The `key` property is used to name the utility classes. The configuration bellow will produce four font styles. The recommended convention is `${family}-${weight}${style}`. 171 | 172 | 1. `font-sans-400` : Inter Regular 173 | 2. `font-sans-400i` : Inter Regular Italic 174 | 3. `font-sans-600i` : Inter Semibold 175 | 4. `font-sans-600i` : Inter Semibold Italic 176 | 177 | ``` 178 | { 179 | key: "sans-400", 180 | familyName: "Inter", 181 | fallback: "sans-serif", 182 | weight: 400, 183 | italic: false, 184 | upm: 2816, 185 | xHeight: 1536, 186 | capHeight: 2048, 187 | lineGap: 0, 188 | ascent: 2728, 189 | descent: -680 190 | }, 191 | { 192 | key: 'sans-400i', 193 | familyName: "Inter", 194 | fallback: 'sans-serif', 195 | file: path.resolve('./fonts/inter/Inter-Italic.woff2'), 196 | }, 197 | { 198 | key: 'sans-600', 199 | familyName: "Inter", 200 | fallback: 'sans-serif', 201 | file: path.resolve('./fonts/inter/Inter-Semibold.woff2'), 202 | }, 203 | { 204 | key: 'sans-600i', 205 | familyName: "Inter", 206 | fallback: 'sans-serif', 207 | file: path.resolve('./fonts/inter/Inter-SemiboldItalic.woff2'), 208 | }, 209 | ``` 210 | 211 | --- 212 | 213 | #### 9/9 - Options : object 214 | 215 | Options properties, are used to enable/disable individual compositor utilities. 216 | 217 | If `useRem` is set to true, compositor will use the root unit value, to transform all spacing and font-size utilities, to relative units. Line-height will be transformed to unitless ratios. 218 | 219 | If `snap` is true, compositor will align each line text to the nearest baseline grid row, otherwise will trim the line-height above the capHeight and below the baseline, and apply a constant lineGap between lines of text. 220 | 221 | - `useRem: boolean` transform to relative units 222 | - `snap: boolean` Align text styles to a baseline grid 223 | `type: boolean` Enable typographic utilities 224 | - `rhythm: boolean` Enable rhythm utilities 225 | - `measure: boolean` Enable measure utilities 226 | - `matrix: boolean` Enable matrix utilities 227 | - `xray: boolean` Enable debug utilities 228 | 229 | ``` 230 | options: { 231 | useRem: true, 232 | snap: true, 233 | type: true, 234 | rhythm: true, 235 | measure: true, 236 | matrix: true, 237 | xray: true, 238 | } 239 | ``` 240 | 241 | --- 242 | 243 | ## Tailwind Utility Classes 244 | 245 | #### 1/7 - Typography 246 | 247 | ##### Font & Font Style 248 | 249 | - font: `font-{font-key}` 250 | 251 | ``` 252 | 253 | // fonts: [ 254 | // { key: "sans-400", ... }, 255 | // { key: 'sans-400i', ... }, 256 | // { key: 'sans-600', ... }, 257 | // { key: 'sans-600i', ... }, 258 | // ], 259 | 260 | // sans semibold italic 261 |

262 | 263 | // sans regular 264 |

265 | 266 | // sans regular italic 267 |

268 | ``` 269 | 270 | ##### Text Style 271 | 272 | - Text Style : `text-{type_scale_index}/{leading_baseline_units}` 273 | 274 | ``` 275 | 276 | // type: [16, 18, 20, 22, 24, 28, 30, 32, 40, 48, 56] 277 | 278 | // sans semibold italic - 56px / leading 3 279 |

280 | 281 | // sans regular - 20px / leading 3 282 |

283 | 284 | // sans regular italic - 18px / leading 2 285 |

286 | ``` 287 | 288 | 289 | --- 290 | 291 | #### 2/7 - Line Width 292 | 293 | - `measure-{measure_scale_index}` 294 | 295 | ``` 296 | // measure: [10, 15, 20, 30, 35, 50, 55, 60, 65] 297 | 298 | // 10ch 299 |

Ad proident quis enim duis commodo.

300 | 301 | // 15ch 302 |

Ad proident quis enim duis commodo.

303 | 304 | // 20ch 305 |

Ad proident quis enim duis commodo.

306 | 307 | // 30ch 308 |

Ad proident quis enim duis commodo.

309 | ``` 310 | 311 | --- 312 | 313 | #### 3/7 - Spacing 314 | 315 | When the tailwind theme is composed, the rhythm scale is transformed to tailwindcss spacing scale and can be used for all spacing utilities, margin, padding and grid-gap. 316 | 317 | - Margin: `m-{rhythm_scale_index}` 318 | - Margin Left: `ml-{rhythm_scale_index}` 319 | - Padding: `p-{rhythm_scale_index}` 320 | - ...etc 321 | 322 | ``` 323 | 324 | // rhythm: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12] 325 | 326 |
327 |

328 | 329 |

330 |

331 | ``` 332 | 333 | --- 334 | 335 | #### 4/7 - Size 336 | 337 | Compositor also applies the spacing scale to tailwind sizing scales, width, min/max width and also height min/max. 338 | 339 | - Height: `h-{rhythm_scale_index}` 340 | - Min Height: `min-h-{rhythm_scale_index}` 341 | - Max Height: `max-h-{rhythm_scale_index}` 342 | - ...etc 343 | - 344 | 345 | ``` 346 |
347 |
349 | ``` 350 | 351 | --- 352 | 353 | #### 5/7 - Lobotomized Owls 354 | 355 | - Vertical rhythm (alias): `rhythm-{rhythm_scale_index}` 356 | - Vertical rhythm: `rhythm-y-{rhythm_scale_index}` 357 | - Horizontal Rhythm: `rhythm-x-{rhythm_scale_index}` 358 | 359 | ``` 360 | 361 |
362 |

363 |

364 | 365 | // render horizontally 366 |

367 |
370 |

371 | ``` 372 | 373 | --- 374 | 375 | #### 6/7 - Matrix Utils 376 | 377 | ##### Matrix 378 | - Matrix: `matrix-{columns_length}` 379 | - Matrix Gap: `matrix-gap-{rhythm_scale_index}` 380 | - Matrix Gap X: `matrix-gap-x-{rhythm_scale_index}` 381 | - Matrix Gap Y: `matrix-gap-y-{rhythm_scale_index}` 382 | 383 | ##### Cells 384 | By default every child of the matrix, will be placed in the next available column and will span for 1 column. In many cases you might not need any cell utilities or only the `cell-span-x` utility. 385 | 386 | - Cell Start X: `cell-start-x-{columns_index}` 387 | - Cell Span X: `cell-span-x-{columns_index}` 388 | 389 | --- 390 | 391 | #### 7/7 - Dev Utils 392 | 393 | - Background grid lines: `bg-baseline` 394 | 395 | ``` 396 |
397 | ``` 398 | -------------------------------------------------------------------------------- /scripts/rollup.base.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | 3 | export const createRollupConfig = pkg => ({ 4 | input: ['src/index.ts'], 5 | // 6 | output: [ 7 | { 8 | file: pkg.main, 9 | format: 'cjs', 10 | exports: 'named', 11 | }, 12 | { 13 | file: pkg.module, 14 | format: 'es', 15 | exports: 'named', 16 | }, 17 | ], 18 | // 19 | external: [...Object.keys(pkg.peerDependencies || {})], 20 | plugins: [ 21 | typescript({ 22 | clean: true, 23 | typescript: require('typescript'), 24 | }), 25 | ], 26 | }); 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.settings.json", 3 | "files": [] // do not remove! 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": false, 4 | "noImplicitAny": false, 5 | "allowSyntheticDefaultImports": true, 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noEmit": true, 12 | "outDir": "./dist", 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "sourceMap": true, 16 | "target": "es5", 17 | "baseUrl": "./", 18 | "noErrorTruncation": true, 19 | "lib": ["es6", "dom"] 20 | }, 21 | "module": "commonjs", 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest"], 3 | "rules": { 4 | "quotemark": [true, "single"], 5 | "no-submodule-imports": false, 6 | "object-literal-sort-keys": false 7 | } 8 | } 9 | --------------------------------------------------------------------------------