├── .github ├── ISSUE_TEMPLATE │ ├── 1.bug_report.yml │ └── config.yml ├── logo.svg └── workflows │ └── main.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── corePlugins │ ├── accessibility.js │ ├── alignContent.js │ ├── alignItems.js │ ├── alignSelf.js │ ├── animation.js │ ├── appearance.js │ ├── backgroundAttachment.js │ ├── backgroundClip.js │ ├── backgroundColor.js │ ├── backgroundImage.js │ ├── backgroundOpacity.js │ ├── backgroundPosition.js │ ├── backgroundRepeat.js │ ├── backgroundSize.js │ ├── borderCollapse.js │ ├── borderColor.js │ ├── borderOpacity.js │ ├── borderRadius.js │ ├── borderStyle.js │ ├── borderWidth.js │ ├── boxShadow.js │ ├── boxSizing.js │ ├── clear.js │ ├── container.js │ ├── css │ │ └── preflight.css │ ├── cursor.js │ ├── display.js │ ├── divideColor.js │ ├── divideOpacity.js │ ├── divideStyle.js │ ├── divideWidth.js │ ├── fill.js │ ├── flex.js │ ├── flexDirection.js │ ├── flexGrow.js │ ├── flexShrink.js │ ├── flexWrap.js │ ├── float.js │ ├── fontFamily.js │ ├── fontSize.js │ ├── fontSmoothing.js │ ├── fontStyle.js │ ├── fontVariantNumeric.js │ ├── fontWeight.js │ ├── gap.js │ ├── gradientColorStops.js │ ├── gridAutoColumns.js │ ├── gridAutoFlow.js │ ├── gridAutoRows.js │ ├── gridColumn.js │ ├── gridColumnEnd.js │ ├── gridColumnStart.js │ ├── gridRow.js │ ├── gridRowEnd.js │ ├── gridRowStart.js │ ├── gridTemplateColumns.js │ ├── gridTemplateRows.js │ ├── height.js │ ├── index.js │ ├── inset.js │ ├── justifyContent.js │ ├── justifyItems.js │ ├── justifySelf.js │ ├── letterSpacing.js │ ├── lineHeight.js │ ├── listStylePosition.js │ ├── listStyleType.js │ ├── margin.js │ ├── maxHeight.js │ ├── maxWidth.js │ ├── minHeight.js │ ├── minWidth.js │ ├── objectFit.js │ ├── objectPosition.js │ ├── opacity.js │ ├── order.js │ ├── outline.js │ ├── overflow.js │ ├── overscrollBehavior.js │ ├── padding.js │ ├── placeContent.js │ ├── placeItems.js │ ├── placeSelf.js │ ├── placeholderColor.js │ ├── placeholderOpacity.js │ ├── pointerEvents.js │ ├── position.js │ ├── preflight.js │ ├── resize.js │ ├── ringColor.js │ ├── ringOffsetColor.js │ ├── ringOffsetWidth.js │ ├── ringOpacity.js │ ├── ringWidth.js │ ├── rotate.js │ ├── scale.js │ ├── skew.js │ ├── space.js │ ├── stroke.js │ ├── strokeWidth.js │ ├── tableLayout.js │ ├── textAlign.js │ ├── textColor.js │ ├── textDecoration.js │ ├── textOpacity.js │ ├── textOverflow.js │ ├── textTransform.js │ ├── transform.js │ ├── transformOrigin.js │ ├── transitionDelay.js │ ├── transitionDuration.js │ ├── transitionProperty.js │ ├── transitionTimingFunction.js │ ├── translate.js │ ├── userSelect.js │ ├── verticalAlign.js │ ├── visibility.js │ ├── whitespace.js │ ├── width.js │ ├── wordBreak.js │ └── zIndex.js ├── index.js ├── lib │ ├── collapseAdjacentRules.js │ ├── expandApplyAtRules.js │ ├── expandTailwindAtRules.js │ ├── generateRules.js │ ├── removeLayerAtRules.js │ ├── rewriteTailwindImports.js │ ├── setupContext.js │ ├── sharedState.js │ └── utils.js └── pluginUtils.js └── tests ├── _customMatchers.js ├── apply.test.css ├── apply.test.html ├── apply.test.js ├── arbitrary-values.test.css ├── arbitrary-values.test.html ├── arbitrary-values.test.js ├── basic-usage.test.css ├── basic-usage.test.html ├── basic-usage.test.js ├── collapse-adjacent-rules.test.css ├── collapse-adjacent-rules.test.html ├── collapse-adjacent-rules.test.js ├── context-reuse.test.html ├── context-reuse.test.js ├── context-reuse.worker.js ├── custom-extractors.test.css ├── custom-extractors.test.html ├── custom-extractors.test.js ├── custom-separator.test.css ├── custom-separator.test.html ├── custom-separator.test.js ├── import-syntax.test.css ├── import-syntax.test.html ├── import-syntax.test.js ├── important-boolean.test.css ├── important-boolean.test.html ├── important-boolean.test.js ├── important-modifier-prefix.test.css ├── important-modifier-prefix.test.html ├── important-modifier-prefix.test.js ├── important-modifier.test.css ├── important-modifier.test.html ├── important-modifier.test.js ├── important-selector.test.css ├── important-selector.test.html ├── important-selector.test.js ├── kitchen-sink.test.css ├── kitchen-sink.test.html ├── kitchen-sink.test.js ├── modify-selectors.test.css ├── modify-selectors.test.html ├── modify-selectors.test.js ├── mutable.test.css ├── mutable.test.html ├── mutable.test.js ├── prefix.fn.test.css ├── prefix.fn.test.html ├── prefix.fn.test.js ├── prefix.test.css ├── prefix.test.html ├── prefix.test.js ├── responsive-and-variants-atrules.test.css ├── responsive-and-variants-atrules.test.html ├── responsive-and-variants-atrules.test.js ├── svelte-syntax.test.css ├── svelte-syntax.test.js ├── svelte-syntax.test.svelte ├── variants.test.css ├── variants.test.html └── variants.test.js /.github/ISSUE_TEMPLATE/1.bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a bug report for @tailwindcss/jit. 3 | title: '' 4 | labels: [] 5 | issue_body: true 6 | body: 7 | - type: input 8 | attributes: 9 | label: What version of @tailwindcss/jit are you using? 10 | description: 'For example: v0.1.3' 11 | validations: 12 | required: true 13 | - type: input 14 | attributes: 15 | label: What version of Node.js are you using? 16 | description: 'For example: v12.0.0' 17 | validations: 18 | required: true 19 | - type: input 20 | attributes: 21 | label: What build tool (or framework if it abstracts the build tool) are you using? 22 | description: 'For example: postcss-cli 8.3.1, Next.js 10.0.9, webpack 5.28.0' 23 | validations: 24 | required: true 25 | - type: input 26 | attributes: 27 | label: What browser are you using? 28 | description: 'For example: Chrome, Safari, or N/A' 29 | validations: 30 | required: true 31 | - type: input 32 | attributes: 33 | label: What operating system are you using? 34 | description: 'For example: macOS, Windows' 35 | validations: 36 | required: true 37 | - type: input 38 | attributes: 39 | label: Reproduction repository 40 | description: A public GitHub repo that includes a minimal reproduction of the bug. Unfortunately we can't provide support without a reproduction, and your issue will be closed and locked with no comment if this is not provided. 41 | validations: 42 | required: true 43 | - type: markdown 44 | attributes: 45 | value: "## Describe your issue\nDescribe the problem you're seeing, any important steps to reproduce and what behavior you expect instead" 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | -------------------------------------------------------------------------------- /.github/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [12.x, 15.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Use Node ${{ matrix.node-version }} 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | 21 | - name: Use cached node_modules 22 | id: cache 23 | uses: actions/cache@v2 24 | with: 25 | path: node_modules 26 | key: nodeModules-${{ hashFiles('**/package-lock.json') }}-${{ matrix.node-version }} 27 | restore-keys: | 28 | nodeModules- 29 | 30 | - name: Install dependencies 31 | if: steps.cache.outputs.cache-hit != 'true' 32 | run: npm install 33 | env: 34 | CI: true 35 | 36 | - name: Test 37 | run: npm run test -- --coverage 38 | env: 39 | CI: true 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | - Nothing yet! 11 | 12 | ## [0.1.18] - 2021-03-31 13 | 14 | ### Added 15 | 16 | - Add support Svelte's `class:` syntax ([#183](https://github.com/tailwindlabs/tailwindcss-jit/issues/183)) 17 | 18 | ## [0.1.17] - 2021-03-28 19 | 20 | ### Added 21 | 22 | - Add support for prefix as a function ([#177](https://github.com/tailwindlabs/tailwindcss-jit/issues/177)) 23 | 24 | ## [0.1.16] - 2021-03-28 25 | 26 | ### Added 27 | 28 | - Add support for selectors in `important` option ([#175](https://github.com/tailwindlabs/tailwindcss-jit/issues/175)) 29 | 30 | ## [0.1.15] - 2021-03-27 31 | 32 | ### Added 33 | 34 | - Add `!font-bold`-style important modifier ([#174](https://github.com/tailwindlabs/tailwindcss-jit/issues/174)) 35 | 36 | ## [0.1.14] - 2021-03-27 37 | 38 | ### Fixed 39 | 40 | - Fix infinite recursion on `]-[]` candidate ([#172](https://github.com/tailwindlabs/tailwindcss-jit/issues/172), [5b366f2](https://github.com/tailwindlabs/tailwindcss-jit/commit/5b366f24bcebc741086c5184001e0f6323d80b68)) 41 | 42 | ## [0.1.13] - 2021-03-27 43 | 44 | ### Fixed 45 | 46 | - Fix infinite recursion issue with TypeScript syntax ([#167](https://github.com/tailwindlabs/tailwindcss-jit/pull/167)) 47 | 48 | ## [0.1.12] - 2021-03-26 49 | 50 | ### Fixed 51 | 52 | - Support custom modifiers with double dashes ([#164](https://github.com/tailwindlabs/tailwindcss-jit/pull/164)) 53 | 54 | ## [0.1.11] - 2021-03-26 55 | 56 | ### Added 57 | 58 | - Add explicit errors for unsupported `@apply` in nested CSS ([#161](https://github.com/tailwindlabs/tailwindcss-jit/pull/161)) 59 | - Add `TAILWIND_DISABLE_TOUCH` environment flag for using native bundler dependency tracking for template files (very experimental/unstable, only works in webpack 5) ([#162](https://github.com/tailwindlabs/tailwindcss-jit/pull/162)) 60 | - Add `TAILWIND_TOUCH_DIR` environment variable for overriding default touch file location (advanced) ([#152](https://github.com/tailwindlabs/tailwindcss-jit/pull/152)) 61 | 62 | ## [0.1.10] - 2021-03-25 63 | 64 | ### Fixed 65 | 66 | - Fix divide-style not generating, and divide-width not handling '0' properly ([#157](https://github.com/tailwindlabs/tailwindcss-jit/pull/157)) 67 | 68 | ## [0.1.9] - 2021-03-25 69 | 70 | ### Fixed 71 | 72 | - Respect order of sibling declarations when mixing `@apply` with regular CSS properties ([#155](https://github.com/tailwindlabs/tailwindcss-jit/pull/155)) 73 | 74 | ## [0.1.8] - 2021-03-24 75 | 76 | ### Added 77 | 78 | - Direct support for @import 'tailwindcss/{layer}' syntax ([#145](https://github.com/tailwindlabs/tailwindcss-jit/pull/145)) 79 | - Support for custom extractors ([#125](https://github.com/tailwindlabs/tailwindcss-jit/pull/125)) 80 | 81 | ### Fixed 82 | 83 | - Fix `@apply` with animation utilities stripping keyframe names ([#150](https://github.com/tailwindlabs/tailwindcss-jit/pull/150)) 84 | - Fix using `@apply` multiple times within a single rule ([#151](https://github.com/tailwindlabs/tailwindcss-jit/pull/151)) 85 | 86 | ## [0.1.7] - 2021-03-22 87 | 88 | ### Fixed 89 | 90 | - Clone nodes to prevent bugs related to rule cache mutation ([#141](https://github.com/tailwindlabs/tailwindcss-jit/pull/141)) 91 | 92 | 93 | ## [0.1.6] - 2021-03-22 94 | 95 | ### Fixed 96 | 97 | - Add initial support for recursive `@apply` ([#136](https://github.com/tailwindlabs/tailwindcss-jit/pull/136)) 98 | 99 | ## [0.1.5] - 2021-03-20 100 | 101 | ### Fixed 102 | 103 | - Fix extending gradient colors directly ([#127](https://github.com/tailwindlabs/tailwindcss-jit/pull/127)) 104 | 105 | ## [0.1.4] - 2021-03-19 106 | 107 | ### Added 108 | 109 | - Support arbitrary values for `transition-duration` ([#99](https://github.com/tailwindlabs/tailwindcss-jit/pull/99)) 110 | - Support completely arbitrary values for `margin` ([#105](https://github.com/tailwindlabs/tailwindcss-jit/pull/105)) 111 | - Support CSS custom properties in arbitrary values ([d628fbc](https://github.com/tailwindlabs/tailwindcss-jit/commit/d628fbc3d393267ce3d1a1d11eed6c3025e6b8f0)) 112 | - Support completely arbitrary values for `inset` ([3ea5421](https://github.com/tailwindlabs/tailwindcss-jit/commit/3ea542170c8631afbfaf5ea341e9860178cf9843) 113 | - Support completely arbitrary `width`/`height`/`min-width`/`max-width`/`min-height`/`max-height` ([76ba529](https://github.com/tailwindlabs/tailwindcss-jit/commit/76ba529d3b120481d153066d348b5dc316cc581f), [6e55976](https://github.com/tailwindlabs/tailwindcss-jit/commit/6e55976ed9c86cc749509c239c751af066d57152)) 114 | 115 | ### Fixed 116 | 117 | - Fix issues when project paths have spaces ([#106](https://github.com/tailwindlabs/tailwindcss-jit/pull/106)) 118 | - Fix negative classes when using a prefix ([#114](https://github.com/tailwindlabs/tailwindcss-jit/pull/114)) 119 | - Fix issues with Windows-style paths ([#118](https://github.com/tailwindlabs/tailwindcss-jit/pull/118)) 120 | - Ensure commas are escaped when applying variants ([#119](https://github.com/tailwindlabs/tailwindcss-jit/pull/119) 121 | 122 | ## [0.1.3] - 2021-03-17 123 | 124 | ### Fixed 125 | 126 | - Escape commas in class names to workaround minifier bug ([#91](https://github.com/tailwindlabs/tailwindcss-jit/pull/91)) 127 | 128 | ## [0.1.2] - 2021-03-17 129 | 130 | ### Fixed 131 | 132 | - Don't apply !important to direct children of at-rules or in keyframes ([#69](https://github.com/tailwindlabs/tailwindcss-jit/pull/69)) 133 | - Fix handling of outline offsets ([#89](https://github.com/tailwindlabs/tailwindcss-jit/pull/89)) 134 | 135 | ## [0.1.1] - 2021-03-15 136 | 137 | ### Fixed 138 | 139 | - Don't collapse adjacent `@font-face` rules ([#30](https://github.com/tailwindlabs/tailwindcss-jit/pull/30)) 140 | 141 | ## [0.1.0] - 2021-03-15 142 | 143 | ### Added 144 | 145 | - Everything! 146 | 147 | [unreleased]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.18...HEAD 148 | [0.1.18]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.17...v0.1.18 149 | [0.1.17]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.16...v0.1.17 150 | [0.1.16]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.15...v0.1.16 151 | [0.1.15]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.14...v0.1.15 152 | [0.1.14]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.13...v0.1.14 153 | [0.1.13]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.12...v0.1.13 154 | [0.1.12]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.11...v0.1.12 155 | [0.1.11]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.10...v0.1.11 156 | [0.1.10]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.9...v0.1.10 157 | [0.1.9]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.8...v0.1.9 158 | [0.1.8]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.7...v0.1.8 159 | [0.1.7]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.6...v0.1.7 160 | [0.1.6]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.5...v0.1.6 161 | [0.1.5]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.4...v0.1.5 162 | [0.1.4]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.3...v0.1.4 163 | [0.1.3]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.2...v0.1.3 164 | [0.1.2]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.1...v0.1.2 165 | [0.1.1]: https://github.com/tailwindlabs/tailwindcss-jit/compare/v0.1.0...v0.1.1 166 | [0.1.0]: https://github.com/tailwindlabs/tailwindcss-jit/releases/tag/v0.1.0 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tailwind Labs 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tailwindcss/jit", 3 | "version": "0.1.18", 4 | "license": "MIT", 5 | "main": "src/index.js", 6 | "repository": "https://github.com/tailwindlabs/tailwindcss-jit", 7 | "scripts": { 8 | "test": "cross-env TAILWIND_MODE=build jest" 9 | }, 10 | "prettier": { 11 | "printWidth": 100, 12 | "semi": false, 13 | "singleQuote": true, 14 | "trailingComma": "es5" 15 | }, 16 | "dependencies": { 17 | "chokidar": "^3.5.1", 18 | "dlv": "^1.1.3", 19 | "fast-glob": "^3.2.5", 20 | "lodash.topath": "^4.5.2", 21 | "normalize-path": "^3.0.0", 22 | "object-hash": "^2.1.1", 23 | "parse-glob": "^3.0.4", 24 | "postcss-selector-parser": "^6.0.4", 25 | "quick-lru": "^5.1.1" 26 | }, 27 | "peerDependencies": { 28 | "postcss": "^8.2.6", 29 | "tailwindcss": "^2.0.3" 30 | }, 31 | "devDependencies": { 32 | "@tailwindcss/aspect-ratio": "^0.2.0", 33 | "autoprefixer": "^10.2.4", 34 | "cross-env": "^7.0.3", 35 | "jest": "^26.6.3", 36 | "postcss": "^8.2.6", 37 | "postcss-cli": "^8.3.1", 38 | "prettier": "^2.2.1", 39 | "tailwindcss": "^2.0.3" 40 | }, 41 | "jest": { 42 | "setupFilesAfterEnv": [ 43 | "/tests/_customMatchers.js" 44 | ] 45 | }, 46 | "browserslist": [ 47 | "> 1%", 48 | "not edge <= 18", 49 | "not safari <= 13", 50 | "not ie 11", 51 | "not op_mini all" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | function indentRecursive(node, indent = 0) { 2 | node.each && 3 | node.each((child, i) => { 4 | if (!child.raws.before || child.raws.before.includes('\n')) { 5 | child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}` 6 | } 7 | child.raws.after = `\n${' '.repeat(indent)}` 8 | indentRecursive(child, indent + 1) 9 | }) 10 | } 11 | 12 | function formatNodes(root) { 13 | indentRecursive(root) 14 | if (root.first) { 15 | root.first.raws.before = '' 16 | } 17 | } 18 | 19 | module.exports = { 20 | plugins: [ 21 | require('./src/index.js')({ 22 | // ... 23 | }), 24 | formatNodes, 25 | 26 | // process.env.NODE_ENV === 'production' ? 27 | // require('autoprefixer'), 28 | // require('cssnano'), 29 | ], 30 | } 31 | -------------------------------------------------------------------------------- /src/corePlugins/accessibility.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.sr-only': { 5 | position: 'absolute', 6 | width: '1px', 7 | height: '1px', 8 | padding: '0', 9 | margin: '-1px', 10 | overflow: 'hidden', 11 | clip: 'rect(0, 0, 0, 0)', 12 | whiteSpace: 'nowrap', 13 | borderWidth: '0', 14 | }, 15 | '.not-sr-only': { 16 | position: 'static', 17 | width: 'auto', 18 | height: 'auto', 19 | padding: '0', 20 | margin: '0', 21 | overflow: 'visible', 22 | clip: 'auto', 23 | whiteSpace: 'normal', 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/corePlugins/alignContent.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.content-center': { 5 | 'align-content': 'center', 6 | }, 7 | '.content-start': { 8 | 'align-content': 'flex-start', 9 | }, 10 | '.content-end': { 11 | 'align-content': 'flex-end', 12 | }, 13 | '.content-between': { 14 | 'align-content': 'space-between', 15 | }, 16 | '.content-around': { 17 | 'align-content': 'space-around', 18 | }, 19 | '.content-evenly': { 20 | 'align-content': 'space-evenly', 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/corePlugins/alignItems.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.items-start': { 5 | 'align-items': 'flex-start', 6 | }, 7 | '.items-end': { 8 | 'align-items': 'flex-end', 9 | }, 10 | '.items-center': { 11 | 'align-items': 'center', 12 | }, 13 | '.items-baseline': { 14 | 'align-items': 'baseline', 15 | }, 16 | '.items-stretch': { 17 | 'align-items': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/alignSelf.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.self-auto': { 5 | 'align-self': 'auto', 6 | }, 7 | '.self-start': { 8 | 'align-self': 'flex-start', 9 | }, 10 | '.self-end': { 11 | 'align-self': 'flex-end', 12 | }, 13 | '.self-center': { 14 | 'align-self': 'center', 15 | }, 16 | '.self-stretch': { 17 | 'align-self': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/animation.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | const parseAnimationValue = require('tailwindcss/lib/util/parseAnimationValue').default 4 | 5 | module.exports = function ({ matchUtilities, jit: { theme } }) { 6 | let keyframes = Object.fromEntries( 7 | Object.entries(theme.keyframes).map(([key, value]) => { 8 | return [ 9 | key, 10 | [ 11 | { 12 | [`@keyframes ${key}`]: value, 13 | }, 14 | { respectVariants: false }, 15 | ], 16 | ] 17 | }) 18 | ) 19 | 20 | let transformValue = transformThemeValue('animation') 21 | matchUtilities({ 22 | animate: [ 23 | (modifier, { theme }) => { 24 | let value = transformValue(theme.animation[modifier]) 25 | 26 | if (modifier === '' || value === undefined) { 27 | return [] 28 | } 29 | 30 | let { name: animationName } = parseAnimationValue(value) 31 | 32 | return [ 33 | keyframes[animationName], 34 | { [nameClass('animate', modifier)]: { animation: value } }, 35 | ].filter(Boolean) 36 | }, 37 | ], 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /src/corePlugins/appearance.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.appearance-none': { appearance: 'none' }, 5 | }) 6 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundAttachment.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.bg-fixed': { 'background-attachment': 'fixed' }, 5 | '.bg-local': { 'background-attachment': 'local' }, 6 | '.bg-scroll': { 'background-attachment': 'scroll' }, 7 | }) 8 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundClip.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.bg-clip-border': { 'background-clip': 'border-box' }, 5 | '.bg-clip-padding': { 'background-clip': 'padding-box' }, 6 | '.bg-clip-content': { 'background-clip': 'content-box' }, 7 | '.bg-clip-text': { 'background-clip': 'text' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundColor.js: -------------------------------------------------------------------------------- 1 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 2 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 3 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 4 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 5 | const { asColor, nameClass } = require('../pluginUtils') 6 | 7 | module.exports = function ({ matchUtilities, jit: { theme } }) { 8 | let colorPalette = flattenColorPalette(theme.backgroundColor) 9 | 10 | matchUtilities({ 11 | bg: (modifier, { theme }) => { 12 | let value = asColor(modifier, colorPalette) 13 | 14 | if (value === undefined) { 15 | return [] 16 | } 17 | 18 | return { 19 | [nameClass('bg', modifier)]: withAlphaVariable({ 20 | color: value, 21 | property: 'background-color', 22 | variable: '--tw-bg-opacity', 23 | }), 24 | } 25 | }, 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundImage.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | bg: (modifier, { theme }) => { 6 | let value = theme.backgroundImage[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('bg', modifier)]: { 'background-image': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme, addVariant, e } }) { 4 | matchUtilities({ 5 | 'bg-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.backgroundOpacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('bg-opacity', modifier)]: { '--tw-bg-opacity': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundPosition.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | bg: (modifier, { theme }) => { 6 | let value = theme.backgroundPosition[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('bg', modifier)]: { 'background-position': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundRepeat.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.bg-repeat': { 'background-repeat': 'repeat' }, 5 | '.bg-no-repeat': { 'background-repeat': 'no-repeat' }, 6 | '.bg-repeat-x': { 'background-repeat': 'repeat-x' }, 7 | '.bg-repeat-y': { 'background-repeat': 'repeat-y' }, 8 | '.bg-repeat-round': { 'background-repeat': 'round' }, 9 | '.bg-repeat-space': { 'background-repeat': 'space' }, 10 | }) 11 | -------------------------------------------------------------------------------- /src/corePlugins/backgroundSize.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | bg: (modifier, { theme }) => { 6 | let value = theme.backgroundSize[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('bg', modifier)]: { 'background-size': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/borderCollapse.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.border-collapse': { 'border-collapse': 'collapse' }, 5 | '.border-separate': { 'border-collapse': 'separate' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/borderColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.borderColor) 8 | 9 | matchUtilities({ 10 | border: (modifier, { theme }) => { 11 | if (modifier === 'DEFAULT') { 12 | return [] 13 | } 14 | 15 | let value = asColor(modifier, colorPalette) 16 | 17 | if (value === undefined) { 18 | return [] 19 | } 20 | 21 | return { 22 | [nameClass('border', modifier)]: withAlphaVariable({ 23 | color: value, 24 | property: 'border-color', 25 | variable: '--tw-border-opacity', 26 | }), 27 | } 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /src/corePlugins/borderOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'border-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.borderOpacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('border-opacity', modifier)]: { '--tw-border-opacity': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/borderRadius.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | rounded: (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['borderRadius']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('rounded', modifier)]: { 'border-radius': value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | 'rounded-t': (modifier, { theme }) => { 17 | let value = asLength(modifier, theme['borderRadius']) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { 24 | [nameClass('rounded-t', modifier)]: { 25 | 'border-top-left-radius': value, 26 | 'border-top-right-radius': value, 27 | }, 28 | } 29 | }, 30 | 'rounded-r': (modifier, { theme }) => { 31 | let value = asLength(modifier, theme['borderRadius']) 32 | 33 | if (value === undefined) { 34 | return [] 35 | } 36 | 37 | return { 38 | [nameClass('rounded-r', modifier)]: { 39 | 'border-top-right-radius': value, 40 | 'border-bottom-right-radius': value, 41 | }, 42 | } 43 | }, 44 | 'rounded-b': (modifier, { theme }) => { 45 | let value = asLength(modifier, theme['borderRadius']) 46 | 47 | if (value === undefined) { 48 | return [] 49 | } 50 | 51 | return { 52 | [nameClass('rounded-b', modifier)]: { 53 | 'border-bottom-right-radius': value, 54 | 'border-bottom-left-radius': value, 55 | }, 56 | } 57 | }, 58 | 'rounded-l': (modifier, { theme }) => { 59 | let value = asLength(modifier, theme['borderRadius']) 60 | 61 | if (value === undefined) { 62 | return [] 63 | } 64 | 65 | return { 66 | [nameClass('rounded-l', modifier)]: { 67 | 'border-top-left-radius': value, 68 | 'border-bottom-left-radius': value, 69 | }, 70 | } 71 | }, 72 | }) 73 | matchUtilities({ 74 | 'rounded-tl': (modifier, { theme }) => { 75 | let value = asLength(modifier, theme['borderRadius']) 76 | 77 | if (value === undefined) { 78 | return [] 79 | } 80 | 81 | return { [nameClass('rounded-tl', modifier)]: { 'border-top-left-radius': value } } 82 | }, 83 | 'rounded-tr': (modifier, { theme }) => { 84 | let value = asLength(modifier, theme['borderRadius']) 85 | 86 | if (value === undefined) { 87 | return [] 88 | } 89 | 90 | return { [nameClass('rounded-tr', modifier)]: { 'border-top-right-radius': value } } 91 | }, 92 | 'rounded-br': (modifier, { theme }) => { 93 | let value = asLength(modifier, theme['borderRadius']) 94 | 95 | if (value === undefined) { 96 | return [] 97 | } 98 | 99 | return { [nameClass('rounded-br', modifier)]: { 'border-bottom-right-radius': value } } 100 | }, 101 | 'rounded-bl': (modifier, { theme }) => { 102 | let value = asLength(modifier, theme['borderRadius']) 103 | 104 | if (value === undefined) { 105 | return [] 106 | } 107 | 108 | return { [nameClass('rounded-bl', modifier)]: { 'border-bottom-left-radius': value } } 109 | }, 110 | }) 111 | } 112 | -------------------------------------------------------------------------------- /src/corePlugins/borderStyle.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.border-solid': { 5 | 'border-style': 'solid', 6 | }, 7 | '.border-dashed': { 8 | 'border-style': 'dashed', 9 | }, 10 | '.border-dotted': { 11 | 'border-style': 'dotted', 12 | }, 13 | '.border-double': { 14 | 'border-style': 'double', 15 | }, 16 | '.border-none': { 17 | 'border-style': 'none', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/borderWidth.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | border: (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['borderWidth']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('border', modifier)]: { 'border-width': value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | 'border-t': (modifier, { theme }) => { 17 | let value = asLength(modifier, theme['borderWidth']) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { [nameClass('border-t', modifier)]: { 'border-top-width': value } } 24 | }, 25 | 'border-r': (modifier, { theme }) => { 26 | let value = asLength(modifier, theme['borderWidth']) 27 | 28 | if (value === undefined) { 29 | return [] 30 | } 31 | 32 | return { [nameClass('border-r', modifier)]: { 'border-right-width': value } } 33 | }, 34 | 'border-b': (modifier, { theme }) => { 35 | let value = asLength(modifier, theme['borderWidth']) 36 | 37 | if (value === undefined) { 38 | return [] 39 | } 40 | 41 | return { [nameClass('border-b', modifier)]: { 'border-bottom-width': value } } 42 | }, 43 | 'border-l': (modifier, { theme }) => { 44 | let value = asLength(modifier, theme['borderWidth']) 45 | 46 | if (value === undefined) { 47 | return [] 48 | } 49 | 50 | return { [nameClass('border-l', modifier)]: { 'border-left-width': value } } 51 | }, 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /src/corePlugins/boxShadow.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | let transformValue = transformThemeValue('boxShadow') 5 | let shadowReset = { 6 | '*': { 7 | '--tw-shadow': '0 0 #0000', 8 | }, 9 | } 10 | 11 | module.exports = function ({ addBase, matchUtilities, jit: { theme } }) { 12 | addBase(shadowReset) 13 | matchUtilities({ 14 | shadow: (modifier, { theme }) => { 15 | modifier = modifier === '' ? 'DEFAULT' : modifier 16 | 17 | let value = transformValue(theme.boxShadow[modifier]) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return [ 24 | { 25 | [nameClass('shadow', modifier)]: { 26 | '--tw-shadow': value === 'none' ? '0 0 #0000' : value, 27 | 'box-shadow': [ 28 | `var(--tw-ring-offset-shadow, 0 0 #0000)`, 29 | `var(--tw-ring-shadow, 0 0 #0000)`, 30 | `var(--tw-shadow)`, 31 | ].join(', '), 32 | }, 33 | }, 34 | ] 35 | }, 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /src/corePlugins/boxSizing.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.box-border': { 'box-sizing': 'border-box' }, 5 | '.box-content': { 'box-sizing': 'content-box' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/clear.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.clear-left': { clear: 'left' }, 5 | '.clear-right': { clear: 'right' }, 6 | '.clear-both': { clear: 'both' }, 7 | '.clear-none': { clear: 'none' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/container.js: -------------------------------------------------------------------------------- 1 | const container = require('tailwindcss/lib/plugins/container') 2 | 3 | module.exports = container() 4 | -------------------------------------------------------------------------------- /src/corePlugins/css/preflight.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Manually forked from SUIT CSS Base: https://github.com/suitcss/base 3 | * A thin layer on top of normalize.css that provides a starting point more 4 | * suitable for web applications. 5 | */ 6 | 7 | /** 8 | * Removes the default spacing and border for appropriate elements. 9 | */ 10 | 11 | blockquote, 12 | dl, 13 | dd, 14 | h1, 15 | h2, 16 | h3, 17 | h4, 18 | h5, 19 | h6, 20 | hr, 21 | figure, 22 | p, 23 | pre { 24 | margin: 0; 25 | } 26 | 27 | button { 28 | background-color: transparent; 29 | background-image: none; 30 | } 31 | 32 | /** 33 | * Work around a Firefox/IE bug where the transparent `button` background 34 | * results in a loss of the default `button` focus styles. 35 | */ 36 | 37 | button:focus { 38 | outline: 1px dotted; 39 | outline: 5px auto -webkit-focus-ring-color; 40 | } 41 | 42 | fieldset { 43 | margin: 0; 44 | padding: 0; 45 | } 46 | 47 | ol, 48 | ul { 49 | list-style: none; 50 | margin: 0; 51 | padding: 0; 52 | } 53 | 54 | /** 55 | * Tailwind custom reset styles 56 | */ 57 | 58 | /** 59 | * 1. Use the user's configured `sans` font-family (with Tailwind's default 60 | * sans-serif font stack as a fallback) as a sane default. 61 | * 2. Use Tailwind's default "normal" line-height so the user isn't forced 62 | * to override it to ensure consistency even when using the default theme. 63 | */ 64 | 65 | html { 66 | font-family: theme('fontFamily.sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); /* 1 */ 67 | line-height: 1.5; /* 2 */ 68 | } 69 | 70 | 71 | /** 72 | * Inherit font-family and line-height from `html` so users can set them as 73 | * a class directly on the `html` element. 74 | */ 75 | 76 | body { 77 | font-family: inherit; 78 | line-height: inherit; 79 | } 80 | 81 | /** 82 | * 1. Prevent padding and border from affecting element width. 83 | * 84 | * We used to set this in the html element and inherit from 85 | * the parent element for everything else. This caused issues 86 | * in shadow-dom-enhanced elements like
where the content 87 | * is wrapped by a div with box-sizing set to `content-box`. 88 | * 89 | * https://github.com/mozdevs/cssremedy/issues/4 90 | * 91 | * 92 | * 2. Allow adding a border to an element by just adding a border-width. 93 | * 94 | * By default, the way the browser specifies that an element should have no 95 | * border is by setting it's border-style to `none` in the user-agent 96 | * stylesheet. 97 | * 98 | * In order to easily add borders to elements by just setting the `border-width` 99 | * property, we change the default border-style for all elements to `solid`, and 100 | * use border-width to hide them instead. This way our `border` utilities only 101 | * need to set the `border-width` property instead of the entire `border` 102 | * shorthand, making our border utilities much more straightforward to compose. 103 | * 104 | * https://github.com/tailwindcss/tailwindcss/pull/116 105 | */ 106 | 107 | *, 108 | ::before, 109 | ::after { 110 | box-sizing: border-box; /* 1 */ 111 | border-width: 0; /* 2 */ 112 | border-style: solid; /* 2 */ 113 | border-color: theme('borderColor.DEFAULT', currentColor); /* 2 */ 114 | } 115 | 116 | /* 117 | * Ensure horizontal rules are visible by default 118 | */ 119 | 120 | hr { 121 | border-top-width: 1px; 122 | } 123 | 124 | /** 125 | * Undo the `border-style: none` reset that Normalize applies to images so that 126 | * our `border-{width}` utilities have the expected effect. 127 | * 128 | * The Normalize reset is unnecessary for us since we default the border-width 129 | * to 0 on all elements. 130 | * 131 | * https://github.com/tailwindcss/tailwindcss/issues/362 132 | */ 133 | 134 | img { 135 | border-style: solid; 136 | } 137 | 138 | textarea { 139 | resize: vertical; 140 | } 141 | 142 | input::placeholder, 143 | textarea::placeholder { 144 | opacity: 1; 145 | color: theme('colors.gray.400', #a1a1aa); 146 | } 147 | 148 | button, 149 | [role="button"] { 150 | cursor: pointer; 151 | } 152 | 153 | table { 154 | border-collapse: collapse; 155 | } 156 | 157 | h1, 158 | h2, 159 | h3, 160 | h4, 161 | h5, 162 | h6 { 163 | font-size: inherit; 164 | font-weight: inherit; 165 | } 166 | 167 | /** 168 | * Reset links to optimize for opt-in styling instead of 169 | * opt-out. 170 | */ 171 | 172 | a { 173 | color: inherit; 174 | text-decoration: inherit; 175 | } 176 | 177 | /** 178 | * Reset form element properties that are easy to forget to 179 | * style explicitly so you don't inadvertently introduce 180 | * styles that deviate from your design system. These styles 181 | * supplement a partial reset that is already applied by 182 | * normalize.css. 183 | */ 184 | 185 | button, 186 | input, 187 | optgroup, 188 | select, 189 | textarea { 190 | padding: 0; 191 | line-height: inherit; 192 | color: inherit; 193 | } 194 | 195 | /** 196 | * Use the configured 'mono' font family for elements that 197 | * are expected to be rendered with a monospace font, falling 198 | * back to the system monospace stack if there is no configured 199 | * 'mono' font family. 200 | */ 201 | 202 | pre, 203 | code, 204 | kbd, 205 | samp { 206 | font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); 207 | } 208 | 209 | /** 210 | * Make replaced elements `display: block` by default as that's 211 | * the behavior you want almost all of the time. Inspired by 212 | * CSS Remedy, with `svg` added as well. 213 | * 214 | * https://github.com/mozdevs/cssremedy/issues/14 215 | */ 216 | 217 | img, 218 | svg, 219 | video, 220 | canvas, 221 | audio, 222 | iframe, 223 | embed, 224 | object { 225 | display: block; 226 | vertical-align: middle; 227 | } 228 | 229 | /** 230 | * Constrain images and videos to the parent width and preserve 231 | * their instrinsic aspect ratio. 232 | * 233 | * https://github.com/mozdevs/cssremedy/issues/14 234 | */ 235 | 236 | img, 237 | video { 238 | max-width: 100%; 239 | height: auto; 240 | } 241 | -------------------------------------------------------------------------------- /src/corePlugins/cursor.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | cursor: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.cursor) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('cursor', modifier)]: { cursor: value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/display.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = [ 4 | createSimpleStaticUtilityPlugin({ 5 | '.block': { display: 'block' }, 6 | '.inline-block': { display: 'inline-block' }, 7 | '.inline': { display: 'inline' }, 8 | '.flex': { display: 'flex' }, 9 | '.inline-flex': { display: 'inline-flex' }, 10 | '.table': { display: 'table' }, 11 | '.table-caption': { display: 'table-caption' }, 12 | '.table-cell': { display: 'table-cell' }, 13 | '.table-column': { display: 'table-column' }, 14 | '.table-column-group': { display: 'table-column-group' }, 15 | '.table-footer-group': { display: 'table-footer-group' }, 16 | '.table-header-group': { display: 'table-header-group' }, 17 | '.table-row-group': { display: 'table-row-group' }, 18 | '.table-row': { display: 'table-row' }, 19 | '.flow-root': { display: 'flow-root' }, 20 | '.grid': { display: 'grid' }, 21 | '.inline-grid': { display: 'inline-grid' }, 22 | '.contents': { display: 'contents' }, 23 | }), 24 | createSimpleStaticUtilityPlugin({ 25 | '.hidden': { display: 'none' }, 26 | }), 27 | ] 28 | -------------------------------------------------------------------------------- /src/corePlugins/divideColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.divideColor) 8 | 9 | // TODO: Make sure there is no issue with DEFAULT here 10 | matchUtilities({ 11 | divide: (modifier, { theme }) => { 12 | let value = asColor(modifier, colorPalette) 13 | 14 | if (value === undefined) { 15 | return [] 16 | } 17 | 18 | return { 19 | [`${nameClass('divide', modifier)} > :not([hidden]) ~ :not([hidden])`]: withAlphaVariable({ 20 | color: colorPalette[modifier], 21 | property: 'border-color', 22 | variable: '--tw-divide-opacity', 23 | }), 24 | } 25 | }, 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/corePlugins/divideOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'divide-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.divideOpacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [`${nameClass('divide-opacity', modifier)} > :not([hidden]) ~ :not([hidden])`]: { 14 | '--tw-divide-opacity': value, 15 | }, 16 | } 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/divideStyle.js: -------------------------------------------------------------------------------- 1 | module.exports = function ({ addUtilities }) { 2 | addUtilities({ 3 | '.divide-solid > :not([hidden]) ~ :not([hidden])': { 4 | 'border-style': 'solid', 5 | }, 6 | '.divide-dashed > :not([hidden]) ~ :not([hidden])': { 7 | 'border-style': 'dashed', 8 | }, 9 | '.divide-dotted > :not([hidden]) ~ :not([hidden])': { 10 | 'border-style': 'dotted', 11 | }, 12 | '.divide-double > :not([hidden]) ~ :not([hidden])': { 13 | 'border-style': 'double', 14 | }, 15 | '.divide-none > :not([hidden]) ~ :not([hidden])': { 16 | 'border-style': 'none', 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/divideWidth.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ addUtilities, matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'divide-x': (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['divideWidth']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | value = value === '0' ? '0px' : value 13 | 14 | return { 15 | [`${nameClass('divide-x', modifier)} > :not([hidden]) ~ :not([hidden])`]: { 16 | '--tw-divide-x-reverse': '0', 17 | 'border-right-width': `calc(${value} * var(--tw-divide-x-reverse))`, 18 | 'border-left-width': `calc(${value} * calc(1 - var(--tw-divide-x-reverse)))`, 19 | }, 20 | } 21 | }, 22 | 'divide-y': (modifier, { theme }) => { 23 | let value = asLength(modifier, theme['divideWidth']) 24 | 25 | if (value === undefined) { 26 | return [] 27 | } 28 | 29 | value = value === '0' ? '0px' : value 30 | 31 | return { 32 | [`${nameClass('divide-y', modifier)} > :not([hidden]) ~ :not([hidden])`]: { 33 | '--tw-divide-y-reverse': '0', 34 | 'border-top-width': `calc(${value} * calc(1 - var(--tw-divide-y-reverse)))`, 35 | 'border-bottom-width': `calc(${value} * var(--tw-divide-y-reverse))`, 36 | }, 37 | } 38 | }, 39 | }) 40 | 41 | addUtilities({ 42 | '.divide-y-reverse > :not([hidden]) ~ :not([hidden])': { 43 | '--tw-divide-y-reverse': '1', 44 | }, 45 | '.divide-x-reverse > :not([hidden]) ~ :not([hidden])': { 46 | '--tw-divide-x-reverse': '1', 47 | }, 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /src/corePlugins/fill.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.fill) 8 | 9 | matchUtilities({ 10 | fill: (modifier, { theme }) => { 11 | let value = asColor(modifier, colorPalette) 12 | 13 | if (value === undefined) { 14 | return [] 15 | } 16 | 17 | return { [nameClass('fill', modifier)]: { fill: toColorValue(value) } } 18 | }, 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /src/corePlugins/flex.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | flex: (modifier, { theme }) => { 7 | let value = theme.flex[modifier] 8 | 9 | if (value === undefined) { 10 | return [] 11 | } 12 | 13 | return { [nameClass('flex', modifier)]: { flex: theme.flex[modifier] } } 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/corePlugins/flexDirection.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.flex-row': { 5 | 'flex-direction': 'row', 6 | }, 7 | '.flex-row-reverse': { 8 | 'flex-direction': 'row-reverse', 9 | }, 10 | '.flex-col': { 11 | 'flex-direction': 'column', 12 | }, 13 | '.flex-col-reverse': { 14 | 'flex-direction': 'column-reverse', 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /src/corePlugins/flexGrow.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'flex-grow': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.flexGrow) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('flex-grow', modifier)]: { 'flex-grow': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/flexShrink.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'flex-shrink': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.flexShrink) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('flex-shrink', modifier)]: { 'flex-shrink': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/flexWrap.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.flex-wrap': { 5 | 'flex-wrap': 'wrap', 6 | }, 7 | '.flex-wrap-reverse': { 8 | 'flex-wrap': 'wrap-reverse', 9 | }, 10 | '.flex-nowrap': { 11 | 'flex-wrap': 'nowrap', 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /src/corePlugins/float.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.float-right': { float: 'right' }, 5 | '.float-left': { float: 'left' }, 6 | '.float-none': { float: 'none' }, 7 | }) 8 | -------------------------------------------------------------------------------- /src/corePlugins/fontFamily.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | let transformValue = transformThemeValue('fontFamily') 6 | 7 | matchUtilities({ 8 | font: (modifier, { theme }) => { 9 | let transformValue = transformThemeValue('fontFamily') 10 | let value = transformValue(theme.fontFamily[modifier]) 11 | 12 | if (modifier === '' || value === undefined) { 13 | return [] 14 | } 15 | 16 | return { [nameClass('font', modifier)]: { 'font-family': transformValue(value) } } 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/fontSize.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | const { isPlainObject } = require('../lib/utils') 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | text: (modifier, { theme }) => { 7 | let value = theme.fontSize[modifier] 8 | 9 | if (value === undefined) { 10 | value = asLength(modifier, {}) 11 | 12 | return value === undefined 13 | ? [] 14 | : { 15 | [nameClass('text', modifier)]: { 16 | 'font-size': value, 17 | }, 18 | } 19 | } 20 | 21 | let [fontSize, options] = Array.isArray(value) ? value : [value] 22 | let { lineHeight, letterSpacing } = isPlainObject(options) 23 | ? options 24 | : { 25 | lineHeight: options, 26 | } 27 | 28 | return { 29 | [nameClass('text', modifier)]: { 30 | 'font-size': fontSize, 31 | ...(lineHeight === undefined 32 | ? {} 33 | : { 34 | 'line-height': lineHeight, 35 | }), 36 | ...(letterSpacing === undefined 37 | ? {} 38 | : { 39 | 'letter-spacing': letterSpacing, 40 | }), 41 | }, 42 | } 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /src/corePlugins/fontSmoothing.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.antialiased': { 5 | '-webkit-font-smoothing': 'antialiased', 6 | '-moz-osx-font-smoothing': 'grayscale', 7 | }, 8 | '.subpixel-antialiased': { 9 | '-webkit-font-smoothing': 'auto', 10 | '-moz-osx-font-smoothing': 'auto', 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /src/corePlugins/fontStyle.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.italic': { 'font-style': 'italic' }, 5 | '.not-italic': { 'font-style': 'normal' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/fontVariantNumeric.js: -------------------------------------------------------------------------------- 1 | let fontVariantBaseStyles = { 2 | '.ordinal, .slashed-zero, .lining-nums, .oldstyle-nums, .proportional-nums, .tabular-nums, .diagonal-fractions, .stacked-fractions': { 3 | '--tw-ordinal': 'var(--tw-empty,/*!*/ /*!*/)', 4 | '--tw-slashed-zero': 'var(--tw-empty,/*!*/ /*!*/)', 5 | '--tw-numeric-figure': 'var(--tw-empty,/*!*/ /*!*/)', 6 | '--tw-numeric-spacing': 'var(--tw-empty,/*!*/ /*!*/)', 7 | '--tw-numeric-fraction': 'var(--tw-empty,/*!*/ /*!*/)', 8 | 'font-variant-numeric': 9 | 'var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)', 10 | }, 11 | } 12 | 13 | module.exports = function ({ matchUtilities }) { 14 | matchUtilities({ 15 | 'normal-nums': fontVariantBaseStyles, 16 | ordinal: fontVariantBaseStyles, 17 | 'slashed-zero': fontVariantBaseStyles, 18 | 'lining-nums': fontVariantBaseStyles, 19 | 'oldstyle-nums': fontVariantBaseStyles, 20 | 'proportional-nums': fontVariantBaseStyles, 21 | 'tabular-nums': fontVariantBaseStyles, 22 | 'diagonal-fractions': fontVariantBaseStyles, 23 | 'stacked-fractions': fontVariantBaseStyles, 24 | }) 25 | 26 | matchUtilities({ 27 | 'normal-nums': { '.normal-nums': { 'font-variant-numeric': 'normal' } }, 28 | ordinal: { '.ordinal': { '--tw-ordinal': 'ordinal' } }, 29 | 'slashed-zero': { '.slashed-zero': { '--tw-slashed-zero': 'slashed-zero' } }, 30 | 'lining-nums': { '.lining-nums': { '--tw-numeric-figure': 'lining-nums' } }, 31 | 'oldstyle-nums': { '.oldstyle-nums': { '--tw-numeric-figure': 'oldstyle-nums' } }, 32 | 'proportional-nums': { '.proportional-nums': { '--tw-numeric-spacing': 'proportional-nums' } }, 33 | 'tabular-nums': { '.tabular-nums': { '--tw-numeric-spacing': 'tabular-nums' } }, 34 | 'diagonal-fractions': { 35 | '.diagonal-fractions': { '--tw-numeric-fraction': 'diagonal-fractions' }, 36 | }, 37 | 'stacked-fractions': { '.stacked-fractions': { '--tw-numeric-fraction': 'stacked-fractions' } }, 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /src/corePlugins/fontWeight.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | font: (modifier, { theme }) => { 7 | let value = theme.fontWeight[modifier] 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('font', modifier)]: { 'font-weight': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gap.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | gap: (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['gap']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('gap', modifier)]: { gap: value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | 'gap-x': (modifier, { theme }) => { 17 | let value = asLength(modifier, theme['gap']) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { [nameClass('gap-x', modifier)]: { 'column-gap': value } } 24 | }, 25 | 'gap-y': (modifier, { theme }) => { 26 | let value = asLength(modifier, theme['gap']) 27 | 28 | if (value === undefined) { 29 | return [] 30 | } 31 | 32 | return { [nameClass('gap-y', modifier)]: { 'row-gap': value } } 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /src/corePlugins/gradientColorStops.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 3 | const toRgba = require('tailwindcss/lib/util/withAlphaVariable').toRgba 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | function transparentTo(value) { 7 | if (typeof value === 'function') { 8 | return value({ opacityValue: 0 }) 9 | } 10 | 11 | try { 12 | const [r, g, b] = toRgba(value) 13 | return `rgba(${r}, ${g}, ${b}, 0)` 14 | } catch (_error) { 15 | return `rgba(255, 255, 255, 0)` 16 | } 17 | } 18 | 19 | module.exports = function ({ matchUtilities, theme }) { 20 | let colorPalette = flattenColorPalette(theme('gradientColorStops')) 21 | 22 | matchUtilities({ 23 | from: (modifier) => { 24 | let value = asColor(modifier, colorPalette) 25 | 26 | if (value === undefined) { 27 | return [] 28 | } 29 | 30 | let transparentToValue = transparentTo(value) 31 | 32 | return { 33 | [nameClass('from', modifier)]: { 34 | '--tw-gradient-from': toColorValue(value, 'from'), 35 | '--tw-gradient-stops': `var(--tw-gradient-from), var(--tw-gradient-to, ${transparentToValue})`, 36 | }, 37 | } 38 | }, 39 | }) 40 | matchUtilities({ 41 | via: (modifier) => { 42 | let value = asColor(modifier, colorPalette) 43 | 44 | if (value === undefined) { 45 | return [] 46 | } 47 | 48 | let transparentToValue = transparentTo(value) 49 | 50 | return { 51 | [nameClass('via', modifier)]: { 52 | '--tw-gradient-stops': `var(--tw-gradient-from), ${toColorValue( 53 | value, 54 | 'via' 55 | )}, var(--tw-gradient-to, ${transparentToValue})`, 56 | }, 57 | } 58 | }, 59 | }) 60 | matchUtilities({ 61 | to: (modifier) => { 62 | let value = asColor(modifier, colorPalette) 63 | 64 | if (value === undefined) { 65 | return [] 66 | } 67 | 68 | return { 69 | [nameClass('to', modifier)]: { 70 | '--tw-gradient-to': toColorValue(value, 'to'), 71 | }, 72 | } 73 | }, 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/corePlugins/gridAutoColumns.js: -------------------------------------------------------------------------------- 1 | const { asList, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'auto-cols': (modifier, { theme }) => { 6 | let value = asList(modifier, theme.gridAutoColumns) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('auto-cols', modifier)]: { 'grid-auto-columns': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gridAutoFlow.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.grid-flow-row': { gridAutoFlow: 'row' }, 5 | '.grid-flow-col': { gridAutoFlow: 'column' }, 6 | '.grid-flow-row-dense': { gridAutoFlow: 'row dense' }, 7 | '.grid-flow-col-dense': { gridAutoFlow: 'column dense' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/gridAutoRows.js: -------------------------------------------------------------------------------- 1 | const { asList, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'auto-rows': (modifier, { theme }) => { 6 | let value = asList(modifier, theme.gridAutoRows) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('auto-rows', modifier)]: { 'grid-auto-rows': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gridColumn.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | col: (modifier, { theme }) => { 7 | if (modifier === '' || theme.gridColumn[modifier] === undefined) { 8 | return [] 9 | } 10 | 11 | return { [nameClass('col', modifier)]: { 'grid-column': theme.gridColumn[modifier] } } 12 | }, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/corePlugins/gridColumnEnd.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | 'col-end': (modifier, { theme }) => { 7 | let transformValue = transformThemeValue('gridColumnEnd') 8 | let value = transformValue(theme.gridColumnEnd[modifier]) 9 | 10 | if (value === undefined) { 11 | return [] 12 | } 13 | 14 | return { [nameClass('col-end', modifier)]: { 'grid-column-end': value } } 15 | }, 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /src/corePlugins/gridColumnStart.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | 'col-start': (modifier, { theme }) => { 7 | let transformValue = transformThemeValue('gridColumnStart') 8 | let value = transformValue(theme.gridColumnStart[modifier]) 9 | 10 | if (value === undefined) { 11 | return [] 12 | } 13 | 14 | return { [nameClass('col-start', modifier)]: { 'grid-column-start': value } } 15 | }, 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /src/corePlugins/gridRow.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | row: (modifier, { theme }) => { 7 | let value = theme.gridRow[modifier] 8 | 9 | if (value === undefined) { 10 | return [] 11 | } 12 | 13 | return { [nameClass('row', modifier)]: { 'grid-row': value } } 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/corePlugins/gridRowEnd.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'row-end': (modifier, { theme }) => { 6 | let value = theme.gridRowEnd[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('row-end', modifier)]: { 'grid-row-end': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gridRowStart.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'row-start': (modifier, { theme }) => { 6 | let value = theme.gridRowStart[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('row-start', modifier)]: { 'grid-row-start': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gridTemplateColumns.js: -------------------------------------------------------------------------------- 1 | const { asList, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'grid-cols': (modifier, { theme }) => { 6 | let value = asList(modifier, theme.gridTemplateColumns) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('grid-cols', modifier)]: { 'grid-template-columns': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/gridTemplateRows.js: -------------------------------------------------------------------------------- 1 | const { asList, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'grid-rows': (modifier, { theme }) => { 6 | let value = asList(modifier, theme.gridTemplateRows) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('grid-rows', modifier)]: { 'grid-template-rows': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/height.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | h: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['height']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('h', modifier)]: { height: value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/inset.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | inset: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['inset']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [nameClass('inset', modifier)]: { top: value, right: value, bottom: value, left: value }, 14 | } 15 | }, 16 | }) 17 | matchUtilities({ 18 | 'inset-x': (modifier, { theme }) => { 19 | let value = asValue(modifier, theme['inset']) 20 | 21 | if (value === undefined) { 22 | return [] 23 | } 24 | 25 | return { [nameClass('inset-x', modifier)]: { left: value, right: value } } 26 | }, 27 | 'inset-y': (modifier, { theme }) => { 28 | let value = asValue(modifier, theme['inset']) 29 | 30 | if (value === undefined) { 31 | return [] 32 | } 33 | 34 | return { [nameClass('inset-y', modifier)]: { top: value, bottom: value } } 35 | }, 36 | }) 37 | matchUtilities({ 38 | top: (modifier, { theme }) => { 39 | let value = asValue(modifier, theme['inset']) 40 | 41 | if (value === undefined) { 42 | return [] 43 | } 44 | 45 | return { [nameClass('top', modifier)]: { top: value } } 46 | }, 47 | right: (modifier, { theme }) => { 48 | let value = asValue(modifier, theme['inset']) 49 | 50 | if (value === undefined) { 51 | return [] 52 | } 53 | 54 | return { [nameClass('right', modifier)]: { right: value } } 55 | }, 56 | bottom: (modifier, { theme }) => { 57 | let value = asValue(modifier, theme['inset']) 58 | 59 | if (value === undefined) { 60 | return [] 61 | } 62 | 63 | return { [nameClass('bottom', modifier)]: { bottom: value } } 64 | }, 65 | left: (modifier, { theme }) => { 66 | let value = asValue(modifier, theme['inset']) 67 | 68 | if (value === undefined) { 69 | return [] 70 | } 71 | 72 | return { [nameClass('left', modifier)]: { left: value } } 73 | }, 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/corePlugins/justifyContent.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.justify-start': { 5 | 'justify-content': 'flex-start', 6 | }, 7 | '.justify-end': { 8 | 'justify-content': 'flex-end', 9 | }, 10 | '.justify-center': { 11 | 'justify-content': 'center', 12 | }, 13 | '.justify-between': { 14 | 'justify-content': 'space-between', 15 | }, 16 | '.justify-around': { 17 | 'justify-content': 'space-around', 18 | }, 19 | '.justify-evenly': { 20 | 'justify-content': 'space-evenly', 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/corePlugins/justifyItems.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.justify-items-auto': { 5 | 'justify-items': 'auto', 6 | }, 7 | '.justify-items-start': { 8 | 'justify-items': 'start', 9 | }, 10 | '.justify-items-end': { 11 | 'justify-items': 'end', 12 | }, 13 | '.justify-items-center': { 14 | 'justify-items': 'center', 15 | }, 16 | '.justify-items-stretch': { 17 | 'justify-items': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/justifySelf.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.justify-self-auto': { 5 | 'justify-self': 'auto', 6 | }, 7 | '.justify-self-start': { 8 | 'justify-self': 'start', 9 | }, 10 | '.justify-self-end': { 11 | 'justify-self': 'end', 12 | }, 13 | '.justify-self-center': { 14 | 'justify-self': 'center', 15 | }, 16 | '.justify-self-stretch': { 17 | 'justify-self': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/letterSpacing.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | tracking: (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['letterSpacing']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('tracking', modifier)]: { 'letter-spacing': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/lineHeight.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | leading: (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['lineHeight']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('leading', modifier)]: { 'line-height': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/listStylePosition.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.list-inside': { 'list-style-position': 'inside' }, 5 | '.list-outside': { 'list-style-position': 'outside' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/listStyleType.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | list: (modifier, { theme }) => { 7 | if (modifier === '' || theme.listStyleType[modifier] === undefined) { 8 | return [] 9 | } 10 | 11 | return { [nameClass('list', modifier)]: { 'list-style-type': theme.listStyleType[modifier] } } 12 | }, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/corePlugins/margin.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | m: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['margin']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('m', modifier)]: { margin: value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | mx: (modifier, { theme }) => { 17 | let value = asValue(modifier, theme['margin']) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { [nameClass('mx', modifier)]: { 'margin-left': value, 'margin-right': value } } 24 | }, 25 | my: (modifier, { theme }) => { 26 | let value = asValue(modifier, theme['margin']) 27 | 28 | if (value === undefined) { 29 | return [] 30 | } 31 | 32 | return { [nameClass('my', modifier)]: { 'margin-top': value, 'margin-bottom': value } } 33 | }, 34 | }) 35 | matchUtilities({ 36 | mt: (modifier, { theme }) => { 37 | let value = asValue(modifier, theme['margin']) 38 | 39 | if (value === undefined) { 40 | return [] 41 | } 42 | 43 | return { [nameClass('mt', modifier)]: { 'margin-top': value } } 44 | }, 45 | mr: (modifier, { theme }) => { 46 | let value = asValue(modifier, theme['margin']) 47 | 48 | if (value === undefined) { 49 | return [] 50 | } 51 | 52 | return { [nameClass('mr', modifier)]: { 'margin-right': value } } 53 | }, 54 | mb: (modifier, { theme }) => { 55 | let value = asValue(modifier, theme['margin']) 56 | 57 | if (value === undefined) { 58 | return [] 59 | } 60 | 61 | return { [nameClass('mb', modifier)]: { 'margin-bottom': value } } 62 | }, 63 | ml: (modifier, { theme }) => { 64 | let value = asValue(modifier, theme['margin']) 65 | 66 | if (value === undefined) { 67 | return [] 68 | } 69 | 70 | return { [nameClass('ml', modifier)]: { 'margin-left': value } } 71 | }, 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /src/corePlugins/maxHeight.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | 'max-h': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['maxHeight']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('max-h', modifier)]: { 'max-height': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/maxWidth.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | 'max-w': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['maxWidth']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('max-w', modifier)]: { 'max-width': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/minHeight.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | 'min-h': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['minHeight']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('min-h', modifier)]: { 'min-height': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/minWidth.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | 'min-w': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['minWidth']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('min-w', modifier)]: { 'min-width': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/objectFit.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.object-contain': { 'object-fit': 'contain' }, 5 | '.object-cover': { 'object-fit': 'cover' }, 6 | '.object-fill': { 'object-fit': 'fill' }, 7 | '.object-none': { 'object-fit': 'none' }, 8 | '.object-scale-down': { 'object-fit': 'scale-down' }, 9 | }) 10 | -------------------------------------------------------------------------------- /src/corePlugins/objectPosition.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | object: (modifier, { theme }) => { 7 | if (modifier === '' || theme.objectPosition[modifier] === undefined) { 8 | return [] 9 | } 10 | 11 | return { 12 | [nameClass('object', modifier)]: { 'object-position': theme.objectPosition[modifier] }, 13 | } 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/corePlugins/opacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | opacity: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.opacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('opacity', modifier)]: { opacity: value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/order.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | order: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.order) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('order', modifier)]: { order: value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/outline.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | outline: (modifier, { theme }) => { 6 | let value = theme.outline[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | let [outline, outlineOffset = '0'] = Array.isArray(value) ? value : [value] 13 | 14 | return { 15 | [nameClass('outline', modifier)]: { 16 | outline, 17 | 'outline-offset': outlineOffset, 18 | }, 19 | } 20 | }, 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /src/corePlugins/overflow.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.overflow-auto': { overflow: 'auto' }, 5 | '.overflow-hidden': { overflow: 'hidden' }, 6 | '.overflow-visible': { overflow: 'visible' }, 7 | '.overflow-scroll': { overflow: 'scroll' }, 8 | '.overflow-x-auto': { 'overflow-x': 'auto' }, 9 | '.overflow-y-auto': { 'overflow-y': 'auto' }, 10 | '.overflow-x-hidden': { 'overflow-x': 'hidden' }, 11 | '.overflow-y-hidden': { 'overflow-y': 'hidden' }, 12 | '.overflow-x-visible': { 'overflow-x': 'visible' }, 13 | '.overflow-y-visible': { 'overflow-y': 'visible' }, 14 | '.overflow-x-scroll': { 'overflow-x': 'scroll' }, 15 | '.overflow-y-scroll': { 'overflow-y': 'scroll' }, 16 | }) 17 | -------------------------------------------------------------------------------- /src/corePlugins/overscrollBehavior.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.overscroll-auto': { 'overscroll-behavior': 'auto' }, 5 | '.overscroll-contain': { 'overscroll-behavior': 'contain' }, 6 | '.overscroll-none': { 'overscroll-behavior': 'none' }, 7 | '.overscroll-y-auto': { 'overscroll-behavior-y': 'auto' }, 8 | '.overscroll-y-contain': { 'overscroll-behavior-y': 'contain' }, 9 | '.overscroll-y-none': { 'overscroll-behavior-y': 'none' }, 10 | '.overscroll-x-auto': { 'overscroll-behavior-x': 'auto' }, 11 | '.overscroll-x-contain': { 'overscroll-behavior-x': 'contain' }, 12 | '.overscroll-x-none': { 'overscroll-behavior-x': 'none' }, 13 | }) 14 | -------------------------------------------------------------------------------- /src/corePlugins/padding.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | p: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['padding']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('p', modifier)]: { padding: value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | px: (modifier, { theme }) => { 17 | let value = asValue(modifier, theme['padding']) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { [nameClass('px', modifier)]: { 'padding-left': value, 'padding-right': value } } 24 | }, 25 | py: (modifier, { theme }) => { 26 | let value = asValue(modifier, theme['padding']) 27 | 28 | if (value === undefined) { 29 | return [] 30 | } 31 | 32 | return { [nameClass('py', modifier)]: { 'padding-top': value, 'padding-bottom': value } } 33 | }, 34 | }) 35 | matchUtilities({ 36 | pt: (modifier, { theme }) => { 37 | let value = asValue(modifier, theme['padding']) 38 | 39 | if (value === undefined) { 40 | return [] 41 | } 42 | 43 | return { [nameClass('pt', modifier)]: { 'padding-top': value } } 44 | }, 45 | pr: (modifier, { theme }) => { 46 | let value = asValue(modifier, theme['padding']) 47 | 48 | if (value === undefined) { 49 | return [] 50 | } 51 | 52 | return { [nameClass('pr', modifier)]: { 'padding-right': value } } 53 | }, 54 | pb: (modifier, { theme }) => { 55 | let value = asValue(modifier, theme['padding']) 56 | 57 | if (value === undefined) { 58 | return [] 59 | } 60 | 61 | return { [nameClass('pb', modifier)]: { 'padding-bottom': value } } 62 | }, 63 | pl: (modifier, { theme }) => { 64 | let value = asValue(modifier, theme['padding']) 65 | 66 | if (value === undefined) { 67 | return [] 68 | } 69 | 70 | return { [nameClass('pl', modifier)]: { 'padding-left': value } } 71 | }, 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /src/corePlugins/placeContent.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.place-content-center': { 5 | 'place-content': 'center', 6 | }, 7 | '.place-content-start': { 8 | 'place-content': 'start', 9 | }, 10 | '.place-content-end': { 11 | 'place-content': 'end', 12 | }, 13 | '.place-content-between': { 14 | 'place-content': 'space-between', 15 | }, 16 | '.place-content-around': { 17 | 'place-content': 'space-around', 18 | }, 19 | '.place-content-evenly': { 20 | 'place-content': 'space-evenly', 21 | }, 22 | '.place-content-stretch': { 23 | 'place-content': 'stretch', 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/corePlugins/placeItems.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.place-items-auto': { 5 | 'place-items': 'auto', 6 | }, 7 | '.place-items-start': { 8 | 'place-items': 'start', 9 | }, 10 | '.place-items-end': { 11 | 'place-items': 'end', 12 | }, 13 | '.place-items-center': { 14 | 'place-items': 'center', 15 | }, 16 | '.place-items-stretch': { 17 | 'place-items': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/placeSelf.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.place-self-auto': { 5 | 'place-self': 'auto', 6 | }, 7 | '.place-self-start': { 8 | 'place-self': 'start', 9 | }, 10 | '.place-self-end': { 11 | 'place-self': 'end', 12 | }, 13 | '.place-self-center': { 14 | 'place-self': 'center', 15 | }, 16 | '.place-self-stretch': { 17 | 'place-self': 'stretch', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/corePlugins/placeholderColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.placeholderColor) 8 | 9 | matchUtilities({ 10 | placeholder: (modifier, { theme }) => { 11 | let value = asColor(modifier, colorPalette) 12 | 13 | if (value === undefined) { 14 | return [] 15 | } 16 | 17 | return { 18 | [`${nameClass('placeholder', modifier)}::placeholder`]: withAlphaVariable({ 19 | color: value, 20 | property: 'color', 21 | variable: '--tw-placeholder-opacity', 22 | }), 23 | } 24 | }, 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /src/corePlugins/placeholderOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'placeholder-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.placeholderOpacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [`${nameClass('placeholder-opacity', modifier)}::placeholder`]: { 14 | '--tw-placeholder-opacity': value, 15 | }, 16 | } 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/pointerEvents.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.pointer-events-none': { 'pointer-events': 'none' }, 5 | '.pointer-events-auto': { 'pointer-events': 'auto' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/position.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.static': { position: 'static' }, 5 | '.fixed': { position: 'fixed' }, 6 | '.absolute': { position: 'absolute' }, 7 | '.relative': { position: 'relative' }, 8 | '.sticky': { 9 | position: 'sticky', 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /src/corePlugins/preflight.js: -------------------------------------------------------------------------------- 1 | const preflight = require('tailwindcss/lib/plugins/preflight').default 2 | 3 | module.exports = preflight() 4 | -------------------------------------------------------------------------------- /src/corePlugins/resize.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.resize-none': { resize: 'none' }, 5 | '.resize-y': { resize: 'vertical' }, 6 | '.resize-x': { resize: 'horizontal' }, 7 | '.resize': { resize: 'both' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/ringColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.ringColor) 8 | 9 | matchUtilities({ 10 | ring: (modifier, { theme }) => { 11 | if (modifier === 'DEFAULT') { 12 | return [] 13 | } 14 | 15 | let value = asColor(modifier, colorPalette) 16 | 17 | if (value === undefined) { 18 | return [] 19 | } 20 | 21 | return { 22 | [nameClass('ring', modifier)]: withAlphaVariable({ 23 | color: value, 24 | property: '--tw-ring-color', 25 | variable: '--tw-ring-opacity', 26 | }), 27 | } 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /src/corePlugins/ringOffsetColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.ringOffsetColor) 8 | 9 | matchUtilities({ 10 | 'ring-offset': (modifier, { theme }) => { 11 | let value = asColor(modifier, colorPalette) 12 | 13 | if (value === undefined) { 14 | return [] 15 | } 16 | 17 | return { 18 | [nameClass('ring-offset', modifier)]: { 19 | '--tw-ring-offset-color': toColorValue(value), 20 | }, 21 | } 22 | }, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/corePlugins/ringOffsetWidth.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'ring-offset': (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['ringOffsetWidth']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [nameClass('ring-offset', modifier)]: { 14 | '--tw-ring-offset-width': value, 15 | }, 16 | } 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/ringOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'ring-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['ringOpacity']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [nameClass('ring-opacity', modifier)]: { 14 | '--tw-ring-opacity': value, 15 | }, 16 | } 17 | }, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/corePlugins/ringWidth.js: -------------------------------------------------------------------------------- 1 | const dlv = require('dlv') 2 | const toRgba = require('tailwindcss/lib/util/withAlphaVariable').toRgba 3 | const { asLength, nameClass } = require('../pluginUtils') 4 | 5 | function safeCall(callback, defaultValue) { 6 | try { 7 | return callback() 8 | } catch (_error) { 9 | return defaultValue 10 | } 11 | } 12 | 13 | module.exports = function ({ addBase, matchUtilities, addUtilities, jit: { theme } }) { 14 | let ringColorDefault = (([r, g, b]) => { 15 | return `rgba(${r}, ${g}, ${b}, ${dlv(theme, ['ringOpacity', 'DEFAULT'], '0.5')})` 16 | })(safeCall(() => toRgba(dlv(theme, ['ringColor', 'DEFAULT'])), ['147', '197', '253'])) 17 | 18 | let ringReset = { 19 | '*': { 20 | '--tw-ring-inset': 'var(--tw-empty,/*!*/ /*!*/)', 21 | '--tw-ring-offset-width': dlv(theme, ['ringOffsetWidth', 'DEFAULT'], '0px'), 22 | '--tw-ring-offset-color': dlv(theme, ['ringOffsetColor', 'DEFAULT'], '#fff'), 23 | '--tw-ring-color': ringColorDefault, 24 | '--tw-ring-offset-shadow': '0 0 #0000', 25 | '--tw-ring-shadow': '0 0 #0000', 26 | }, 27 | } 28 | 29 | addBase(ringReset) 30 | 31 | matchUtilities({ 32 | ring: (modifier, { theme }) => { 33 | let value = asLength(modifier, theme['ringWidth']) 34 | 35 | if (value === undefined) { 36 | return [] 37 | } 38 | 39 | return [ 40 | { 41 | [nameClass('ring', modifier)]: { 42 | '--tw-ring-offset-shadow': `var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)`, 43 | '--tw-ring-shadow': `var(--tw-ring-inset) 0 0 0 calc(${value} + var(--tw-ring-offset-width)) var(--tw-ring-color)`, 44 | 'box-shadow': [ 45 | `var(--tw-ring-offset-shadow)`, 46 | `var(--tw-ring-shadow)`, 47 | `var(--tw-shadow, 0 0 #0000)`, 48 | ].join(', '), 49 | }, 50 | }, 51 | ] 52 | }, 53 | }) 54 | 55 | addUtilities({ 56 | '.ring-inset': { 57 | '--tw-ring-inset': 'inset', 58 | }, 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /src/corePlugins/rotate.js: -------------------------------------------------------------------------------- 1 | const { asAngle, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | rotate: (modifier, { theme }) => { 6 | let value = asAngle(modifier, theme.rotate) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('rotate', modifier)]: { '--tw-rotate': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/scale.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | scale: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.scale) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('scale', modifier)]: { '--tw-scale-x': value, '--tw-scale-y': value } } 13 | }, 14 | }) 15 | matchUtilities({ 16 | 'scale-x': (modifier, { theme }) => { 17 | let value = asValue(modifier, theme.scale) 18 | 19 | if (value === undefined) { 20 | return [] 21 | } 22 | 23 | return { [nameClass('scale-x', modifier)]: { '--tw-scale-x': value } } 24 | }, 25 | 'scale-y': (modifier, { theme }) => { 26 | let value = asValue(modifier, theme.scale) 27 | 28 | if (value === undefined) { 29 | return [] 30 | } 31 | 32 | return { [nameClass('scale-y', modifier)]: { '--tw-scale-y': value } } 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /src/corePlugins/skew.js: -------------------------------------------------------------------------------- 1 | const { asAngle, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'skew-x': (modifier, { theme }) => { 6 | let value = asAngle(modifier, theme.skew) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('skew-x', modifier)]: { '--tw-skew-x': value } } 13 | }, 14 | 'skew-y': (modifier, { theme }) => { 15 | let value = asAngle(modifier, theme.skew) 16 | 17 | if (value === undefined) { 18 | return [] 19 | } 20 | 21 | return { [nameClass('skew-y', modifier)]: { '--tw-skew-y': value } } 22 | }, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/corePlugins/space.js: -------------------------------------------------------------------------------- 1 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 2 | const { asLength, nameClass } = require('../pluginUtils') 3 | 4 | module.exports = function ({ matchUtilities, addUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | 'space-x': (modifier, { theme }) => { 7 | let value = asLength(modifier, theme['space']) 8 | 9 | if (value === undefined) { 10 | return [] 11 | } 12 | 13 | return { 14 | [`${nameClass('space-x', modifier)} > :not([hidden]) ~ :not([hidden])`]: { 15 | '--tw-space-x-reverse': '0', 16 | 'margin-right': `calc(${value} * var(--tw-space-x-reverse))`, 17 | 'margin-left': `calc(${value} * calc(1 - var(--tw-space-x-reverse)))`, 18 | }, 19 | } 20 | }, 21 | 'space-y': (modifier, { theme }) => { 22 | let value = asLength(modifier, theme['space']) 23 | 24 | if (value === undefined) { 25 | return [] 26 | } 27 | 28 | return { 29 | [`${nameClass('space-y', modifier)} > :not([hidden]) ~ :not([hidden])`]: { 30 | '--tw-space-y-reverse': '0', 31 | 'margin-top': `calc(${value} * calc(1 - var(--tw-space-y-reverse)))`, 32 | 'margin-bottom': `calc(${value} * var(--tw-space-y-reverse))`, 33 | }, 34 | } 35 | }, 36 | }) 37 | 38 | addUtilities({ 39 | '.space-y-reverse > :not([hidden]) ~ :not([hidden])': { 40 | '--tw-space-y-reverse': '1', 41 | }, 42 | '.space-x-reverse > :not([hidden]) ~ :not([hidden])': { 43 | '--tw-space-x-reverse': '1', 44 | }, 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /src/corePlugins/stroke.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.stroke) 8 | 9 | matchUtilities({ 10 | stroke: (modifier, { theme }) => { 11 | let value = asColor(modifier, colorPalette) 12 | 13 | if (value === undefined) { 14 | return [] 15 | } 16 | 17 | return { [nameClass('stroke', modifier)]: { stroke: toColorValue(value) } } 18 | }, 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /src/corePlugins/strokeWidth.js: -------------------------------------------------------------------------------- 1 | const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default 2 | const { asLength, nameClass } = require('../pluginUtils') 3 | 4 | module.exports = function ({ matchUtilities, jit: { theme } }) { 5 | matchUtilities({ 6 | stroke: (modifier, { theme }) => { 7 | let value = asLength(modifier, theme['strokeWidth']) 8 | 9 | if (value === undefined) { 10 | return [] 11 | } 12 | 13 | return { [nameClass('stroke', modifier)]: { 'stroke-width': value } } 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/corePlugins/tableLayout.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.table-auto': { 'table-layout': 'auto' }, 5 | '.table-fixed': { 'table-layout': 'fixed' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/textAlign.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.text-left': { 'text-align': 'left' }, 5 | '.text-center': { 'text-align': 'center' }, 6 | '.text-right': { 'text-align': 'right' }, 7 | '.text-justify': { 'text-align': 'justify' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/textColor.js: -------------------------------------------------------------------------------- 1 | const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default 2 | const withAlphaVariable = require('tailwindcss/lib/util/withAlphaVariable').default 3 | const toColorValue = require('tailwindcss/lib/util/toColorValue').default 4 | const { asColor, nameClass } = require('../pluginUtils') 5 | 6 | module.exports = function ({ matchUtilities, jit: { theme } }) { 7 | let colorPalette = flattenColorPalette(theme.textColor) 8 | 9 | matchUtilities({ 10 | text: (modifier, { theme }) => { 11 | let value = asColor(modifier, colorPalette) 12 | 13 | if (value === undefined) { 14 | return [] 15 | } 16 | 17 | return { 18 | [nameClass('text', modifier)]: withAlphaVariable({ 19 | color: value, 20 | property: 'color', 21 | variable: '--tw-text-opacity', 22 | }), 23 | } 24 | }, 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /src/corePlugins/textDecoration.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.underline': { 'text-decoration': 'underline' }, 5 | '.line-through': { 'text-decoration': 'line-through' }, 6 | '.no-underline': { 'text-decoration': 'none' }, 7 | }) 8 | -------------------------------------------------------------------------------- /src/corePlugins/textOpacity.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'text-opacity': (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.textOpacity) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('text-opacity', modifier)]: { '--tw-text-opacity': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/textOverflow.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = [ 4 | createSimpleStaticUtilityPlugin({ 5 | '.truncate': { 6 | overflow: 'hidden', 7 | 'text-overflow': 'ellipsis', 8 | 'white-space': 'nowrap', 9 | }, 10 | }), 11 | createSimpleStaticUtilityPlugin({ 12 | '.overflow-ellipsis': { 'text-overflow': 'ellipsis' }, 13 | '.overflow-clip': { 'text-overflow': 'clip' }, 14 | }), 15 | ] 16 | -------------------------------------------------------------------------------- /src/corePlugins/textTransform.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.uppercase': { 'text-transform': 'uppercase' }, 5 | '.lowercase': { 'text-transform': 'lowercase' }, 6 | '.capitalize': { 'text-transform': 'capitalize' }, 7 | '.normal-case': { 'text-transform': 'none' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/transform.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.transform': { 5 | '--tw-translate-x': '0', 6 | '--tw-translate-y': '0', 7 | '--tw-rotate': '0', 8 | '--tw-skew-x': '0', 9 | '--tw-skew-y': '0', 10 | '--tw-scale-x': '1', 11 | '--tw-scale-y': '1', 12 | transform: [ 13 | 'translateX(var(--tw-translate-x))', 14 | 'translateY(var(--tw-translate-y))', 15 | 'rotate(var(--tw-rotate))', 16 | 'skewX(var(--tw-skew-x))', 17 | 'skewY(var(--tw-skew-y))', 18 | 'scaleX(var(--tw-scale-x))', 19 | 'scaleY(var(--tw-scale-y))', 20 | ].join(' '), 21 | }, 22 | '.transform-gpu': { 23 | '--tw-translate-x': '0', 24 | '--tw-translate-y': '0', 25 | '--tw-rotate': '0', 26 | '--tw-skew-x': '0', 27 | '--tw-skew-y': '0', 28 | '--tw-scale-x': '1', 29 | '--tw-scale-y': '1', 30 | transform: [ 31 | 'translate3d(var(--tw-translate-x), var(--tw-translate-y), 0)', 32 | 'rotate(var(--tw-rotate))', 33 | 'skewX(var(--tw-skew-x))', 34 | 'skewY(var(--tw-skew-y))', 35 | 'scaleX(var(--tw-scale-x))', 36 | 'scaleY(var(--tw-scale-y))', 37 | ].join(' '), 38 | }, 39 | '.transform-none': { transform: 'none' }, 40 | }) 41 | -------------------------------------------------------------------------------- /src/corePlugins/transformOrigin.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | origin: (modifier, { theme }) => { 6 | let value = theme.transformOrigin[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('origin', modifier)]: { 'transform-origin': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/transitionDelay.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | delay: (modifier, { theme }) => { 6 | let value = theme.transitionDelay[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { 13 | [nameClass('delay', modifier)]: { 'transition-delay': value }, 14 | } 15 | }, 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /src/corePlugins/transitionDuration.js: -------------------------------------------------------------------------------- 1 | const { nameClass, asValue } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | duration: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.transitionDuration) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('duration', modifier)]: { 'transition-duration': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/transitionProperty.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | let defaultTimingFunction = theme.transitionTimingFunction.DEFAULT 5 | let defaultDuration = theme.transitionDuration.DEFAULT 6 | 7 | matchUtilities({ 8 | transition: (modifier, { theme }) => { 9 | let value = theme.transitionProperty[modifier] 10 | 11 | if (value === undefined) { 12 | return [] 13 | } 14 | 15 | return { 16 | [nameClass('transition', modifier)]: { 17 | 'transition-property': value, 18 | ...(value === 'none' 19 | ? {} 20 | : { 21 | 'transition-timing-function': defaultTimingFunction, 22 | 'transition-duration': defaultDuration, 23 | }), 24 | }, 25 | } 26 | }, 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /src/corePlugins/transitionTimingFunction.js: -------------------------------------------------------------------------------- 1 | const { nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | ease: (modifier, { theme }) => { 6 | let value = theme.transitionTimingFunction[modifier] 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('ease', modifier)]: { 'transition-timing-function': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/translate.js: -------------------------------------------------------------------------------- 1 | const { asLength, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | 'translate-x': (modifier, { theme }) => { 6 | let value = asLength(modifier, theme['translate']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('translate-x', modifier)]: { '--tw-translate-x': value } } 13 | }, 14 | 'translate-y': (modifier, { theme }) => { 15 | let value = asLength(modifier, theme['translate']) 16 | 17 | if (value === undefined) { 18 | return [] 19 | } 20 | 21 | return { [nameClass('translate-y', modifier)]: { '--tw-translate-y': value } } 22 | }, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/corePlugins/userSelect.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.select-none': { 'user-select': 'none' }, 5 | '.select-text': { 'user-select': 'text' }, 6 | '.select-all': { 'user-select': 'all' }, 7 | '.select-auto': { 'user-select': 'auto' }, 8 | }) 9 | -------------------------------------------------------------------------------- /src/corePlugins/verticalAlign.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.align-baseline': { 'vertical-align': 'baseline' }, 5 | '.align-top': { 'vertical-align': 'top' }, 6 | '.align-middle': { 'vertical-align': 'middle' }, 7 | '.align-bottom': { 'vertical-align': 'bottom' }, 8 | '.align-text-top': { 'vertical-align': 'text-top' }, 9 | '.align-text-bottom': { 'vertical-align': 'text-bottom' }, 10 | }) 11 | -------------------------------------------------------------------------------- /src/corePlugins/visibility.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.visible': { visibility: 'visible' }, 5 | '.invisible': { visibility: 'hidden' }, 6 | }) 7 | -------------------------------------------------------------------------------- /src/corePlugins/whitespace.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.whitespace-normal': { 'white-space': 'normal' }, 5 | '.whitespace-nowrap': { 'white-space': 'nowrap' }, 6 | '.whitespace-pre': { 'white-space': 'pre' }, 7 | '.whitespace-pre-line': { 'white-space': 'pre-line' }, 8 | '.whitespace-pre-wrap': { 'white-space': 'pre-wrap' }, 9 | }) 10 | -------------------------------------------------------------------------------- /src/corePlugins/width.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities }) { 4 | matchUtilities({ 5 | w: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme['width']) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('w', modifier)]: { width: value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/corePlugins/wordBreak.js: -------------------------------------------------------------------------------- 1 | const { createSimpleStaticUtilityPlugin } = require('../pluginUtils') 2 | 3 | module.exports = createSimpleStaticUtilityPlugin({ 4 | '.break-normal': { 5 | 'overflow-wrap': 'normal', 6 | 'word-break': 'normal', 7 | }, 8 | '.break-words': { 9 | 'overflow-wrap': 'break-word', 10 | }, 11 | '.break-all': { 'word-break': 'break-all' }, 12 | }) 13 | -------------------------------------------------------------------------------- /src/corePlugins/zIndex.js: -------------------------------------------------------------------------------- 1 | const { asValue, nameClass } = require('../pluginUtils') 2 | 3 | module.exports = function ({ matchUtilities, jit: { theme } }) { 4 | matchUtilities({ 5 | z: (modifier, { theme }) => { 6 | let value = asValue(modifier, theme.zIndex) 7 | 8 | if (value === undefined) { 9 | return [] 10 | } 11 | 12 | return { [nameClass('z', modifier)]: { 'z-index': value } } 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | 3 | const evaluateTailwindFunctions = require('tailwindcss/lib/lib/evaluateTailwindFunctions').default 4 | const substituteScreenAtRules = require('tailwindcss/lib/lib/substituteScreenAtRules').default 5 | 6 | const rewriteTailwindImports = require('./lib/rewriteTailwindImports') 7 | const setupContext = require('./lib/setupContext') 8 | const removeLayerAtRules = require('./lib/removeLayerAtRules') 9 | const expandTailwindAtRules = require('./lib/expandTailwindAtRules') 10 | const expandApplyAtRules = require('./lib/expandApplyAtRules') 11 | const collapseAdjacentRules = require('./lib/collapseAdjacentRules') 12 | 13 | const { env } = require('./lib/sharedState') 14 | 15 | module.exports = (configOrPath = {}) => { 16 | return { 17 | postcssPlugin: 'tailwindcss-jit', 18 | plugins: [ 19 | env.DEBUG && 20 | function (root) { 21 | console.log('\n') 22 | console.time('JIT TOTAL') 23 | return root 24 | }, 25 | function (root, result) { 26 | function registerDependency(fileName, type = 'dependency') { 27 | result.messages.push({ 28 | type, 29 | plugin: 'tailwindcss-jit', 30 | parent: result.opts.from, 31 | file: fileName, 32 | }) 33 | } 34 | 35 | rewriteTailwindImports(root) 36 | 37 | let context = setupContext(configOrPath)(result, root) 38 | 39 | if (!env.TAILWIND_DISABLE_TOUCH) { 40 | if (context.configPath !== null) { 41 | registerDependency(context.configPath) 42 | } 43 | } 44 | 45 | return postcss([ 46 | removeLayerAtRules(context), 47 | expandTailwindAtRules(context, registerDependency), 48 | expandApplyAtRules(context), 49 | evaluateTailwindFunctions(context.tailwindConfig), 50 | substituteScreenAtRules(context.tailwindConfig), 51 | collapseAdjacentRules(context), 52 | ]).process(root, { from: undefined }) 53 | }, 54 | env.DEBUG && 55 | function (root) { 56 | console.timeEnd('JIT TOTAL') 57 | console.log('\n') 58 | return root 59 | }, 60 | ], 61 | } 62 | } 63 | 64 | module.exports.postcss = true 65 | -------------------------------------------------------------------------------- /src/lib/collapseAdjacentRules.js: -------------------------------------------------------------------------------- 1 | let comparisonMap = { 2 | atrule: ['name', 'params'], 3 | rule: ['selector'], 4 | } 5 | let types = new Set(Object.keys(comparisonMap)) 6 | 7 | function collapseAdjacentRules(context) { 8 | return (root) => { 9 | let currentRule = null 10 | root.each((node) => { 11 | if (!types.has(node.type)) { 12 | currentRule = null 13 | return 14 | } 15 | 16 | if (currentRule === null) { 17 | currentRule = node 18 | return 19 | } 20 | 21 | let properties = comparisonMap[node.type] 22 | 23 | if (node.type === 'atrule' && node.name === 'font-face') { 24 | currentRule = node 25 | } else if (properties.every((property) => node[property] === currentRule[property])) { 26 | currentRule.append(node.nodes) 27 | node.remove() 28 | } else { 29 | currentRule = node 30 | } 31 | }) 32 | } 33 | } 34 | 35 | module.exports = collapseAdjacentRules 36 | -------------------------------------------------------------------------------- /src/lib/removeLayerAtRules.js: -------------------------------------------------------------------------------- 1 | function removeLayerAtRules(context) { 2 | return (root) => { 3 | root.walkAtRules((rule) => { 4 | if (['layer', 'responsive', 'variants'].includes(rule.name)) { 5 | rule.remove() 6 | } 7 | }) 8 | } 9 | } 10 | 11 | module.exports = removeLayerAtRules 12 | -------------------------------------------------------------------------------- /src/lib/rewriteTailwindImports.js: -------------------------------------------------------------------------------- 1 | function rewriteTailwindImports(root) { 2 | root.walkAtRules('import', (atRule) => { 3 | if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { 4 | atRule.name = 'tailwind' 5 | atRule.params = 'base' 6 | } else if ( 7 | atRule.params === '"tailwindcss/components"' || 8 | atRule.params === "'tailwindcss/components'" 9 | ) { 10 | atRule.name = 'tailwind' 11 | atRule.params = 'components' 12 | } else if ( 13 | atRule.params === '"tailwindcss/utilities"' || 14 | atRule.params === "'tailwindcss/utilities'" 15 | ) { 16 | atRule.name = 'tailwind' 17 | atRule.params = 'utilities' 18 | } else if ( 19 | atRule.params === '"tailwindcss/screens"' || 20 | atRule.params === "'tailwindcss/screens'" 21 | ) { 22 | atRule.name = 'tailwind' 23 | atRule.params = 'screens' 24 | } 25 | }) 26 | } 27 | 28 | module.exports = rewriteTailwindImports 29 | -------------------------------------------------------------------------------- /src/lib/sharedState.js: -------------------------------------------------------------------------------- 1 | const LRU = require('quick-lru') 2 | 3 | module.exports = { 4 | env: { 5 | TAILWIND_MODE: process.env.TAILWIND_MODE, 6 | NODE_ENV: process.env.NODE_ENV, 7 | DEBUG: process.env.DEBUG !== undefined, 8 | TAILWIND_DISABLE_TOUCH: process.env.TAILWIND_DISABLE_TOUCH !== undefined, 9 | TAILWIND_TOUCH_DIR: process.env.TAILWIND_TOUCH_DIR, 10 | }, 11 | contextMap: new Map(), 12 | configContextMap: new Map(), 13 | contextSourcesMap: new Map(), 14 | contentMatchCache: new LRU({ maxSize: 25000 }), 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwindUtils = { 3 | escapeClassName: require('tailwindcss/lib/util/escapeClassName').default, 4 | nameClass: require('tailwindcss/lib/util/nameClass').default, 5 | } 6 | 7 | // Takes our lightweight rule structure and turns it into a PostCSS node. 8 | // This is likely a hot path and should be as optimized as possible. We 9 | // use a cache for the actual rules so that we are never recreating them 10 | // if we've already done the work, but we need to be careful we don't 11 | // mutate these nodes after we get them because we reuse the same 12 | // reference. 13 | function toPostCssNode(rule, postCssNodeCache) { 14 | if (postCssNodeCache.has(rule)) { 15 | return postCssNodeCache.get(rule) 16 | } 17 | 18 | let [selector, childRule] = rule 19 | let node 20 | 21 | if (selector[0] === '@') { 22 | let name = selector.slice(1, selector.indexOf(' ')) 23 | let params = selector.slice(selector.indexOf(' ') + 1) 24 | node = postcss.atRule({ name, params }) 25 | 26 | if (Array.isArray(childRule)) { 27 | // It's a rule tuple 28 | node.append( 29 | childRule.map((rule) => { 30 | return toPostCssNode(rule, postCssNodeCache) 31 | }) 32 | ) 33 | } else { 34 | // It's an object, like pairs in keyframes 35 | for (let property in childRule) { 36 | node.append( 37 | postcss.decl({ 38 | prop: property, 39 | value: childRule[property], 40 | }) 41 | ) 42 | } 43 | } 44 | } else { 45 | // Regular rule (like a class), children are definitely declarations, 46 | // not other rules 47 | node = postcss.rule({ 48 | selector: rule[0], 49 | nodes: Object.entries(rule[1]).map(([prop, value]) => { 50 | return postcss.decl({ prop, value }) 51 | }), 52 | }) 53 | } 54 | 55 | postCssNodeCache.set(rule, node) 56 | 57 | return node 58 | } 59 | 60 | function bigSign(bigIntValue) { 61 | return (bigIntValue > 0n) - (bigIntValue < 0n) 62 | } 63 | 64 | function isPlainObject(value) { 65 | if (Object.prototype.toString.call(value) !== '[object Object]') { 66 | return false 67 | } 68 | 69 | const prototype = Object.getPrototypeOf(value) 70 | return prototype === null || prototype === Object.prototype 71 | } 72 | 73 | // workaround for minifier bug which splits selectors by commas, 74 | // even when they are escaped (e.g. \,) 75 | function escapeCommas(className) { 76 | return className.replace(/\\,/g, '\\2c ') 77 | } 78 | 79 | function escapeClassName(...args) { 80 | return escapeCommas(tailwindUtils.escapeClassName(...args)) 81 | } 82 | 83 | function nameClass(...args) { 84 | return escapeCommas(tailwindUtils.nameClass(...args)) 85 | } 86 | 87 | /** 88 | * Clone generated and/or cached nodes to ensure no future 89 | * postcss plugins can mutate the rules and mess up our cache 90 | * 91 | * @param {import('postcss').Node[]} nodes 92 | * */ 93 | function cloneNodes(nodes) { 94 | return nodes.map((node) => node.clone()) 95 | } 96 | 97 | module.exports = { 98 | toPostCssNode, 99 | bigSign, 100 | isPlainObject, 101 | escapeClassName, 102 | escapeCommas, 103 | nameClass, 104 | cloneNodes, 105 | } 106 | -------------------------------------------------------------------------------- /src/pluginUtils.js: -------------------------------------------------------------------------------- 1 | const selectorParser = require('postcss-selector-parser') 2 | const postcss = require('postcss') 3 | const { toRgba } = require('tailwindcss/lib/util/withAlphaVariable') 4 | const { nameClass, escapeCommas } = require('./lib/utils') 5 | 6 | function updateAllClasses(selectors, updateClass) { 7 | let parser = selectorParser((selectors) => { 8 | selectors.walkClasses((sel) => { 9 | let updatedClass = updateClass(sel.value, { 10 | withPseudo(className, pseudo) { 11 | sel.parent.insertAfter(sel, selectorParser.pseudo({ value: `:${pseudo}` })) 12 | return className 13 | }, 14 | }) 15 | sel.value = updatedClass 16 | if (sel.raws && sel.raws.value) { 17 | sel.raws.value = escapeCommas(sel.raws.value) 18 | } 19 | }) 20 | }) 21 | 22 | let result = parser.processSync(selectors) 23 | 24 | return result 25 | } 26 | 27 | function updateLastClasses(selectors, updateClass) { 28 | let parser = selectorParser((selectors) => { 29 | selectors.each((sel) => { 30 | let lastClass = sel.filter(({ type }) => type === 'class').pop() 31 | 32 | if (lastClass === undefined) { 33 | return 34 | } 35 | 36 | let updatedClass = updateClass(lastClass.value, { 37 | withPseudo(className, pseudo) { 38 | lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `:${pseudo}` })) 39 | return className 40 | }, 41 | }) 42 | lastClass.value = updatedClass 43 | if (lastClass.raws && lastClass.raws.value) { 44 | lastClass.raws.value = escapeCommas(lastClass.raws.value) 45 | } 46 | }) 47 | }) 48 | let result = parser.processSync(selectors) 49 | 50 | return result 51 | } 52 | 53 | function transformAllSelectors(transformSelector, wrap = null) { 54 | return ({ container }) => { 55 | container.walkRules((rule) => { 56 | let transformed = rule.selector.split(',').map(transformSelector).join(',') 57 | rule.selector = transformed 58 | return rule 59 | }) 60 | 61 | if (wrap) { 62 | let wrapper = wrap() 63 | wrapper.append(container.nodes) 64 | container.append(wrapper) 65 | } 66 | } 67 | } 68 | 69 | function transformAllClasses(transformClass, wrap = null) { 70 | return ({ container }) => { 71 | container.walkRules((rule) => { 72 | let selector = rule.selector 73 | let variantSelector = updateAllClasses(selector, transformClass) 74 | rule.selector = variantSelector 75 | return rule 76 | }) 77 | } 78 | } 79 | 80 | function transformLastClasses(transformClass, wrap = null) { 81 | return ({ container }) => { 82 | container.walkRules((rule) => { 83 | let selector = rule.selector 84 | let variantSelector = updateLastClasses(selector, transformClass) 85 | rule.selector = variantSelector 86 | return rule 87 | }) 88 | 89 | if (wrap) { 90 | let wrapper = wrap() 91 | wrapper.append(container.nodes) 92 | container.append(wrapper) 93 | } 94 | } 95 | } 96 | 97 | function asValue(modifier, lookup = {}, { validate = () => true, transform = (v) => v } = {}) { 98 | let value = lookup[modifier] 99 | 100 | if (value !== undefined) { 101 | return value 102 | } 103 | 104 | if (modifier[0] !== '[' || modifier[modifier.length - 1] !== ']') { 105 | return undefined 106 | } 107 | 108 | value = modifier.slice(1, -1) 109 | 110 | if (!validate(value)) { 111 | return undefined 112 | } 113 | 114 | // add spaces around operators inside calc() that do not follow an operator or ( 115 | return transform(value).replace(/(?<=^calc\(.+?)(? { 121 | let unitsPattern = `(?:${units.join('|')})` 122 | return ( 123 | new RegExp(`${unitsPattern}$`).test(value) || 124 | new RegExp(`^calc\\(.+?${unitsPattern}`).test(value) 125 | ) 126 | }, 127 | transform: (value) => { 128 | return value 129 | }, 130 | }) 131 | } 132 | 133 | module.exports = { 134 | nameClass, 135 | updateAllClasses, 136 | updateLastClasses, 137 | transformAllSelectors, 138 | transformAllClasses, 139 | transformLastClasses, 140 | createSimpleStaticUtilityPlugin(styles) { 141 | return function ({ matchUtilities }) { 142 | matchUtilities( 143 | Object.entries(styles).reduce((newStyles, [selector, rules]) => { 144 | let result = { [selector]: rules } 145 | newStyles[selector.slice(1)] = [result] 146 | return newStyles 147 | }, {}) 148 | ) 149 | } 150 | }, 151 | asValue, 152 | asList(modifier, lookup = {}) { 153 | return asValue(modifier, lookup, { 154 | transform: (value) => { 155 | return postcss.list 156 | .comma(value) 157 | .map((v) => v.replace(/,/g, ', ')) 158 | .join(' ') 159 | }, 160 | }) 161 | }, 162 | asColor(modifier, lookup = {}) { 163 | return asValue(modifier, lookup, { 164 | validate: (value) => { 165 | try { 166 | toRgba(value) 167 | return true 168 | } catch (e) { 169 | return false 170 | } 171 | }, 172 | }) 173 | }, 174 | asAngle(modifier, lookup = {}) { 175 | return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup) 176 | }, 177 | asLength(modifier, lookup = {}) { 178 | return asUnit( 179 | modifier, 180 | [ 181 | 'cm', 182 | 'mm', 183 | 'Q', 184 | 'in', 185 | 'pc', 186 | 'pt', 187 | 'px', 188 | 'em', 189 | 'ex', 190 | 'ch', 191 | 'rem', 192 | 'lh', 193 | 'vw', 194 | 'vh', 195 | 'vmin', 196 | 'vmax', 197 | '%', 198 | ], 199 | lookup 200 | ) 201 | }, 202 | } 203 | -------------------------------------------------------------------------------- /tests/_customMatchers.js: -------------------------------------------------------------------------------- 1 | const prettier = require('prettier') 2 | const diff = require('jest-diff').default 3 | 4 | function format(input) { 5 | return prettier.format(input, { 6 | parser: 'css', 7 | printWidth: 100, 8 | }) 9 | } 10 | 11 | expect.extend({ 12 | // Compare two CSS strings with all whitespace removed 13 | // This is probably naive but it's fast and works well enough. 14 | toMatchCss(received, argument) { 15 | const options = { 16 | comment: 'stripped(received) === stripped(argument)', 17 | isNot: this.isNot, 18 | promise: this.promise, 19 | } 20 | 21 | let formattedReceived = format(received) 22 | let formattedArgument = format(argument) 23 | 24 | const pass = formattedReceived === formattedArgument 25 | 26 | const message = pass 27 | ? () => { 28 | return ( 29 | this.utils.matcherHint('toMatchCss', undefined, undefined, options) + 30 | '\n\n' + 31 | `Expected: not ${this.utils.printExpected(formattedReceived)}\n` + 32 | `Received: ${this.utils.printReceived(formattedArgument)}` 33 | ) 34 | } 35 | : () => { 36 | const actual = formattedReceived 37 | const expected = formattedArgument 38 | 39 | const diffString = diff(expected, actual, { 40 | expand: this.expand, 41 | }) 42 | 43 | return ( 44 | this.utils.matcherHint('toMatchCss', undefined, undefined, options) + 45 | '\n\n' + 46 | (diffString && diffString.includes('- Expect') 47 | ? `Difference:\n\n${diffString}` 48 | : `Expected: ${this.utils.printExpected(expected)}\n` + 49 | `Received: ${this.utils.printReceived(actual)}`) 50 | ) 51 | } 52 | 53 | return { actual: received, message, pass } 54 | }, 55 | }) 56 | -------------------------------------------------------------------------------- /tests/apply.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/apply.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | const { currentTestName } = expect.getState() 8 | 9 | return postcss([tailwind(config)]).process(input, { 10 | from: `${path.resolve(__filename)}?test=${currentTestName}`, 11 | }) 12 | } 13 | 14 | test('@apply', () => { 15 | let config = { 16 | darkMode: 'class', 17 | purge: [path.resolve(__dirname, './apply.test.html')], 18 | corePlugins: { preflight: false }, 19 | theme: {}, 20 | plugins: [], 21 | } 22 | 23 | let css = ` 24 | @tailwind base; 25 | @tailwind components; 26 | @tailwind utilities; 27 | 28 | @layer components { 29 | .basic-example { 30 | @apply px-4 py-2 bg-blue-500 rounded-md; 31 | } 32 | .class-order { 33 | @apply pt-4 pr-1 px-3 py-7 p-8; 34 | } 35 | .with-additional-properties { 36 | font-weight: 500; 37 | @apply text-right; 38 | } 39 | .variants { 40 | @apply xl:focus:font-black hover:font-bold lg:font-light focus:font-medium font-semibold; 41 | } 42 | .only-variants { 43 | @apply xl:focus:font-black hover:font-bold lg:font-light focus:font-medium; 44 | } 45 | .apply-group-variant { 46 | @apply group-hover:text-center lg:group-hover:text-left; 47 | } 48 | .apply-dark-variant { 49 | @apply dark:text-center dark:hover:text-right lg:dark:text-left; 50 | } 51 | .apply-custom-utility { 52 | @apply custom-util hover:custom-util lg:custom-util xl:focus:custom-util; 53 | } 54 | .multiple, .selectors { 55 | @apply px-4 py-2 bg-blue-500 rounded-md; 56 | } 57 | .multiple-variants, .selectors-variants { 58 | @apply hover:text-center active:text-right lg:focus:text-left; 59 | } 60 | .multiple-group, .selectors-group { 61 | @apply group-hover:text-center lg:group-hover:text-left; 62 | } 63 | /* TODO: This works but the generated CSS is unnecessarily verbose. */ 64 | .complex-utilities { 65 | @apply ordinal tabular-nums focus:diagonal-fractions shadow-lg hover:shadow-xl; 66 | } 67 | .basic-nesting-parent { 68 | .basic-nesting-child { 69 | @apply font-bold hover:font-normal; 70 | } 71 | } 72 | .use-base-only-a { 73 | @apply font-bold; 74 | } 75 | .use-base-only-b { 76 | @apply use-base-only-a font-normal; 77 | } 78 | .use-dependant-only-a { 79 | @apply font-bold; 80 | } 81 | .use-dependant-only-b { 82 | @apply use-dependant-only-a font-normal; 83 | } 84 | .btn { 85 | @apply font-bold py-2 px-4 rounded; 86 | } 87 | .btn-blue { 88 | @apply btn bg-blue-500 hover:bg-blue-700 text-white; 89 | } 90 | .recursive-apply-a { 91 | @apply font-black sm:font-thin; 92 | } 93 | .recursive-apply-b { 94 | @apply recursive-apply-a font-semibold md:font-extralight; 95 | } 96 | .recursive-apply-c { 97 | @apply recursive-apply-b font-bold lg:font-light; 98 | } 99 | .use-with-other-properties-base { 100 | color: green; 101 | @apply font-bold; 102 | } 103 | .use-with-other-properties-component { 104 | @apply use-with-other-properties-base; 105 | } 106 | .add-sibling-properties { 107 | padding: 2rem; 108 | @apply px-4 hover:px-2 lg:px-10 xl:focus:px-1; 109 | padding-top: 3px; 110 | @apply use-with-other-properties-base; 111 | } 112 | 113 | h1 { 114 | @apply text-2xl lg:text-2xl sm:text-3xl; 115 | } 116 | h2 { 117 | @apply text-2xl; 118 | @apply lg:text-2xl; 119 | @apply sm:text-2xl; 120 | } 121 | } 122 | 123 | @layer utilities { 124 | .custom-util { 125 | custom: stuff; 126 | } 127 | 128 | .foo { 129 | @apply animate-spin; 130 | } 131 | 132 | .bar { 133 | @apply animate-pulse !important; 134 | } 135 | } 136 | ` 137 | 138 | return run(css, config).then((result) => { 139 | let expectedPath = path.resolve(__dirname, './apply.test.css') 140 | let expected = fs.readFileSync(expectedPath, 'utf8') 141 | 142 | expect(result.css).toMatchCss(expected) 143 | }) 144 | }) 145 | 146 | test('@apply error with unknown utility', async () => { 147 | let config = { 148 | darkMode: 'class', 149 | purge: [path.resolve(__dirname, './apply.test.html')], 150 | corePlugins: { preflight: false }, 151 | plugins: [], 152 | } 153 | 154 | let css = ` 155 | @tailwind components; 156 | @tailwind utilities; 157 | 158 | @layer components { 159 | .foo { 160 | @apply a-utility-that-does-not-exist; 161 | } 162 | } 163 | ` 164 | 165 | await expect(run(css, config)).rejects.toThrowError('class does not exist') 166 | }) 167 | 168 | test('@apply error with nested @screen', async () => { 169 | let config = { 170 | darkMode: 'class', 171 | purge: [path.resolve(__dirname, './apply.test.html')], 172 | corePlugins: { preflight: false }, 173 | plugins: [], 174 | } 175 | 176 | let css = ` 177 | @tailwind components; 178 | @tailwind utilities; 179 | 180 | @layer components { 181 | .foo { 182 | @screen md { 183 | @apply text-black; 184 | } 185 | } 186 | } 187 | ` 188 | 189 | await expect(run(css, config)).rejects.toThrowError( 190 | '@apply is not supported within nested at-rules like @screen' 191 | ) 192 | }) 193 | 194 | test('@apply error with nested @anyatrulehere', async () => { 195 | let config = { 196 | darkMode: 'class', 197 | purge: [path.resolve(__dirname, './apply.test.html')], 198 | corePlugins: { preflight: false }, 199 | plugins: [], 200 | } 201 | 202 | let css = ` 203 | @tailwind components; 204 | @tailwind utilities; 205 | 206 | @layer components { 207 | .foo { 208 | @genie { 209 | @apply text-black; 210 | } 211 | } 212 | } 213 | ` 214 | 215 | await expect(run(css, config)).rejects.toThrowError( 216 | '@apply is not supported within nested at-rules like @genie' 217 | ) 218 | }) 219 | -------------------------------------------------------------------------------- /tests/arbitrary-values.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .inset-\[11px\] { 11 | top: 11px; 12 | right: 11px; 13 | bottom: 11px; 14 | left: 11px; 15 | } 16 | .mt-\[clamp\(30px\2c 100px\)\] { 17 | margin-top: clamp(30px, 100px); 18 | } 19 | .h-\[3\.23rem\] { 20 | height: 3.23rem; 21 | } 22 | .h-\[calc\(100\%\+1rem\)\] { 23 | height: calc(100% + 1rem); 24 | } 25 | .h-\[var\(--height\)\] { 26 | height: var(--height); 27 | } 28 | .max-h-\[3\.23rem\] { 29 | max-height: 3.23rem; 30 | } 31 | .max-h-\[calc\(100\%\+1rem\)\] { 32 | max-height: calc(100% + 1rem); 33 | } 34 | .max-h-\[var\(--height\)\] { 35 | max-height: var(--height); 36 | } 37 | .min-h-\[3\.23rem\] { 38 | min-height: 3.23rem; 39 | } 40 | .min-h-\[calc\(100\%\+1rem\)\] { 41 | min-height: calc(100% + 1rem); 42 | } 43 | .min-h-\[var\(--height\)\] { 44 | min-height: var(--height); 45 | } 46 | .w-\[3\.23rem\] { 47 | width: 3.23rem; 48 | } 49 | .w-\[calc\(100\%\+1rem\)\] { 50 | width: calc(100% + 1rem); 51 | } 52 | .w-\[var\(--width\)\] { 53 | width: var(--width); 54 | } 55 | .min-w-\[3\.23rem\] { 56 | min-width: 3.23rem; 57 | } 58 | .min-w-\[calc\(100\%\+1rem\)\] { 59 | min-width: calc(100% + 1rem); 60 | } 61 | .min-w-\[var\(--width\)\] { 62 | min-width: var(--width); 63 | } 64 | .max-w-\[3\.23rem\] { 65 | max-width: 3.23rem; 66 | } 67 | .max-w-\[calc\(100\%\+1rem\)\] { 68 | max-width: calc(100% + 1rem); 69 | } 70 | .max-w-\[var\(--width\)\] { 71 | max-width: var(--width); 72 | } 73 | .rotate-\[23deg\] { 74 | --tw-rotate: 23deg; 75 | } 76 | .rotate-\[2\.3rad\] { 77 | --tw-rotate: 2.3rad; 78 | } 79 | .rotate-\[401grad\] { 80 | --tw-rotate: 401grad; 81 | } 82 | .rotate-\[1\.5turn\] { 83 | --tw-rotate: 1.5turn; 84 | } 85 | .grid-cols-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] { 86 | grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; 87 | } 88 | .space-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) { 89 | --tw-space-x-reverse: 0; 90 | margin-right: calc(20cm * var(--tw-space-x-reverse)); 91 | margin-left: calc(20cm * calc(1 - var(--tw-space-x-reverse))); 92 | } 93 | .space-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { 94 | --tw-space-x-reverse: 0; 95 | margin-right: calc(calc(20% - 1cm) * var(--tw-space-x-reverse)); 96 | margin-left: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-x-reverse))); 97 | } 98 | .border-\[2\.5px\] { 99 | border-width: 2.5px; 100 | } 101 | .border-\[\#f00\] { 102 | --tw-border-opacity: 1; 103 | border-color: rgba(255, 0, 0, var(--tw-border-opacity)); 104 | } 105 | .bg-\[\#0f0\] { 106 | --tw-bg-opacity: 1; 107 | background-color: rgba(0, 255, 0, var(--tw-bg-opacity)); 108 | } 109 | .bg-\[\#ff0000\] { 110 | --tw-bg-opacity: 1; 111 | background-color: rgba(255, 0, 0, var(--tw-bg-opacity)); 112 | } 113 | .bg-\[\#0000ffcc\] { 114 | background-color: #0000ffcc; 115 | } 116 | .bg-\[rgb\(123\2c 123\2c 123\)\] { 117 | --tw-bg-opacity: 1; 118 | background-color: rgba(123, 123, 123, var(--tw-bg-opacity)); 119 | } 120 | .bg-\[rgba\(123\2c 123\2c 123\2c 0\.5\)\] { 121 | background-color: rgba(123, 123, 123, 0.5); 122 | } 123 | .bg-\[hsl\(0\2c 100\%\2c 50\%\)\] { 124 | --tw-bg-opacity: 1; 125 | background-color: rgba(255, 0, 0, var(--tw-bg-opacity)); 126 | } 127 | .bg-\[hsla\(0\2c 100\%\2c 50\%\2c 0\.3\)\] { 128 | background-color: hsla(0, 100%, 50%, 0.3); 129 | } 130 | .bg-opacity-\[0\.11\] { 131 | --tw-bg-opacity: 0.11; 132 | } 133 | .p-\[var\(--app-padding\)\] { 134 | padding: var(--app-padding); 135 | } 136 | .text-\[2\.23rem\] { 137 | font-size: 2.23rem; 138 | } 139 | .duration-\[2s\] { 140 | transition-duration: 2s; 141 | } 142 | .duration-\[var\(--app-duration\)\] { 143 | transition-duration: var(--app-duration); 144 | } 145 | @media (min-width: 1024px) { 146 | .lg\:grid-cols-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] { 147 | grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /tests/arbitrary-values.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/arbitrary-values.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('arbitrary values', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './arbitrary-values.test.html')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [], 16 | } 17 | 18 | let css = ` 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | ` 23 | 24 | return run(css, config).then((result) => { 25 | let expectedPath = path.resolve(__dirname, './arbitrary-values.test.css') 26 | let expected = fs.readFileSync(expectedPath, 'utf8') 27 | 28 | expect(result.css).toMatchCss(expected) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/basic-usage.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | 130 |
131 |
132 |
133 |
134 | 135 | 136 | -------------------------------------------------------------------------------- /tests/basic-usage.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('basic usage', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './basic-usage.test.html')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [], 16 | } 17 | 18 | let css = ` 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | ` 23 | 24 | return run(css, config).then((result) => { 25 | let expectedPath = path.resolve(__dirname, './basic-usage.test.css') 26 | let expected = fs.readFileSync(expectedPath, 'utf8') 27 | 28 | expect(result.css).toMatchCss(expected) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/collapse-adjacent-rules.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | @font-face { 11 | font-family: 'Poppins'; 12 | src: url('/fonts/Poppins.woff2') format('woff2'), url('/fonts/Poppins.woff') format('woff'); 13 | } 14 | @font-face { 15 | font-family: 'Proxima Nova'; 16 | src: url('/fonts/ProximaNova.woff2') format('woff2'), 17 | url('/fonts/ProximaNova.woff') format('woff'); 18 | } 19 | @font-face { 20 | font-family: 'Inter'; 21 | src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); 22 | } 23 | @font-face { 24 | font-family: 'Gilroy'; 25 | src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); 26 | } 27 | @page { 28 | margin: 1cm; 29 | } 30 | .font-bold { 31 | font-weight: 700; 32 | } 33 | @media (min-width: 640px) { 34 | .sm\:text-center { 35 | text-align: center; 36 | } 37 | .sm\:font-bold { 38 | font-weight: 700; 39 | } 40 | } 41 | @media (min-width: 768px) { 42 | .md\:text-center { 43 | text-align: center; 44 | } 45 | .md\:font-bold { 46 | font-weight: 700; 47 | } 48 | } 49 | @media (min-width: 1024px) { 50 | .lg\:text-center { 51 | text-align: center; 52 | } 53 | .lg\:font-bold { 54 | font-weight: 700; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/collapse-adjacent-rules.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/collapse-adjacent-rules.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('collapse adjacent rules', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './collapse-adjacent-rules.test.html')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [], 16 | } 17 | 18 | let css = ` 19 | @tailwind base; 20 | @font-face { 21 | font-family: "Inter"; 22 | src: url("/fonts/Inter.woff2") format("woff2"), 23 | url("/fonts/Inter.woff") format("woff"); 24 | } 25 | @font-face { 26 | font-family: "Gilroy"; 27 | src: url("/fonts/Gilroy.woff2") format("woff2"), 28 | url("/fonts/Gilroy.woff") format("woff"); 29 | } 30 | @page { 31 | margin: 1cm; 32 | } 33 | @tailwind components; 34 | @tailwind utilities; 35 | @layer base { 36 | @font-face { 37 | font-family: "Poppins"; 38 | src: url("/fonts/Poppins.woff2") format("woff2"), 39 | url("/fonts/Poppins.woff") format("woff"); 40 | } 41 | @font-face { 42 | font-family: "Proxima Nova"; 43 | src: url("/fonts/ProximaNova.woff2") format("woff2"), 44 | url("/fonts/ProximaNova.woff") format("woff"); 45 | } 46 | } 47 | ` 48 | 49 | return run(css, config).then((result) => { 50 | let expectedPath = path.resolve(__dirname, './collapse-adjacent-rules.test.css') 51 | let expected = fs.readFileSync(expectedPath, 'utf8') 52 | 53 | expect(result.css).toMatchCss(expected) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /tests/context-reuse.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/context-reuse.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const process = require('child_process') 3 | const { promisify } = require('util') 4 | const exec = promisify(process.exec) 5 | 6 | test('a build re-uses the context across multiple files with the same config', async () => { 7 | const filepath = path.resolve(__dirname, './context-reuse.worker.js') 8 | 9 | const { stdout } = await exec(`node ${filepath}`) 10 | 11 | const results = JSON.parse(stdout.trim()) 12 | 13 | expect(results[0].activeContexts).toBe(1) 14 | expect(results[1].activeContexts).toBe(1) 15 | expect(results[2].activeContexts).toBe(1) 16 | expect(results[3].activeContexts).toBe(1) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/context-reuse.worker.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path") 3 | const postcss = require("postcss") 4 | const tailwind = require("../src/index.js") 5 | const sharedState = require("../src/lib/sharedState.js") 6 | const configPath = path.resolve(__dirname, './context-reuse.tailwind.config.js') 7 | 8 | function run(input, config = {}, from = null) { 9 | from = from || path.resolve(__filename) 10 | 11 | return postcss([tailwind(config)]).process(input, { from }) 12 | } 13 | 14 | async function runTest() { 15 | let messages = [] 16 | 17 | let config = { 18 | darkMode: 'class', 19 | purge: [path.resolve(__dirname, './context-reuse.test.html')], 20 | corePlugins: { preflight: false }, 21 | theme: {}, 22 | plugins: [], 23 | } 24 | 25 | let from = path.resolve(__filename) 26 | 27 | fs.writeFileSync(configPath, `module.exports = ${JSON.stringify(config)};`) 28 | 29 | let results = [ 30 | await run(`@tailwind utilities;`, configPath, `${from}?id=1`), 31 | await run(`body { @apply bg-blue-400; }`, configPath, `${from}?id=2`), 32 | await run(`body { @apply text-red-400; }`, configPath, `${from}?id=3`), 33 | await run(`body { @apply mb-4; }`, configPath, `${from}?id=4`), 34 | ] 35 | 36 | results.forEach(() => { 37 | messages.push({ 38 | activeContexts: sharedState.contextSourcesMap.size, 39 | }) 40 | }) 41 | 42 | process.stdout.write(JSON.stringify(messages)) 43 | } 44 | 45 | runTest().finally(() => { 46 | fs.unlinkSync(configPath) 47 | }) 48 | -------------------------------------------------------------------------------- /tests/custom-extractors.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .bg-white { 11 | --tw-bg-opacity: 1; 12 | background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); 13 | } 14 | .text-indigo-500 { 15 | --tw-text-opacity: 1; 16 | color: rgba(99, 102, 241, var(--tw-text-opacity)); 17 | } 18 | -------------------------------------------------------------------------------- /tests/custom-extractors.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
hello world
12 | text-red-500 shouldn't appear in the output 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/custom-extractors.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const fs = require('fs') 3 | const path = require('path') 4 | 5 | function run(input, config = {}) { 6 | jest.resetModules() 7 | const tailwind = require('../src/index.js') 8 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 9 | } 10 | 11 | function customExtractor(content) { 12 | const matches = content.match(/class="([^"]+)"/) 13 | return matches ? matches[1].split(/\s+/) : [] 14 | } 15 | 16 | const css = ` 17 | @tailwind base; 18 | @tailwind components; 19 | @tailwind utilities; 20 | ` 21 | const expectedPath = path.resolve(__dirname, './custom-extractors.test.css') 22 | const expected = fs.readFileSync(expectedPath, 'utf8') 23 | 24 | test('defaultExtractor', () => { 25 | let config = { 26 | purge: { 27 | content: [path.resolve(__dirname, './custom-extractors.test.html')], 28 | options: { 29 | defaultExtractor: customExtractor, 30 | }, 31 | }, 32 | corePlugins: { preflight: false }, 33 | theme: {}, 34 | plugins: [], 35 | } 36 | 37 | return run(css, config).then((result) => { 38 | expect(result.css).toMatchCss(expected) 39 | }) 40 | }) 41 | 42 | test('extractors array', () => { 43 | let config = { 44 | purge: { 45 | content: [path.resolve(__dirname, './custom-extractors.test.html')], 46 | options: { 47 | extractors: [ 48 | { 49 | extractor: customExtractor, 50 | extensions: ['html'], 51 | }, 52 | ], 53 | }, 54 | }, 55 | corePlugins: { preflight: false }, 56 | theme: {}, 57 | plugins: [], 58 | } 59 | 60 | return run(css, config).then((result) => { 61 | expect(result.css).toMatchCss(expected) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /tests/custom-separator.test.css: -------------------------------------------------------------------------------- 1 | .group_hover .group-hover_focus-within_text-left:focus-within { 2 | text-align: left; 3 | } 4 | [dir='rtl'] .rtl_active_text-center:active { 5 | text-align: center; 6 | } 7 | @media (prefers-reduced-motion: no-preference) { 8 | .motion-safe_hover_text-center:hover { 9 | text-align: center; 10 | } 11 | } 12 | .dark .dark_focus_text-left:focus { 13 | text-align: left; 14 | } 15 | @media (min-width: 768px) { 16 | .md_hover_text-right:hover { 17 | text-align: right; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/custom-separator.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /tests/custom-separator.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('custom separator', () => { 11 | let config = { 12 | darkMode: 'class', 13 | purge: [path.resolve(__dirname, './custom-separator.test.html')], 14 | separator: '_', 15 | corePlugins: {}, 16 | theme: {}, 17 | plugins: [], 18 | } 19 | 20 | let css = `@tailwind utilities` 21 | 22 | return run(css, config).then((result) => { 23 | let expectedPath = path.resolve(__dirname, './custom-separator.test.css') 24 | let expected = fs.readFileSync(expectedPath, 'utf8') 25 | 26 | expect(result.css).toMatchCss(expected) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/import-syntax.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | h1 { 11 | font-size: 32px; 12 | } 13 | .container { 14 | width: 100%; 15 | } 16 | @media (min-width: 640px) { 17 | .container { 18 | max-width: 640px; 19 | } 20 | } 21 | @media (min-width: 768px) { 22 | .container { 23 | max-width: 768px; 24 | } 25 | } 26 | @media (min-width: 1024px) { 27 | .container { 28 | max-width: 1024px; 29 | } 30 | } 31 | @media (min-width: 1280px) { 32 | .container { 33 | max-width: 1280px; 34 | } 35 | } 36 | @media (min-width: 1536px) { 37 | .container { 38 | max-width: 1536px; 39 | } 40 | } 41 | .mt-6 { 42 | margin-top: 1.5rem; 43 | } 44 | .bg-black { 45 | --tw-bg-opacity: 1; 46 | background-color: rgba(0, 0, 0, var(--tw-bg-opacity)); 47 | } 48 | @media (min-width: 768px) { 49 | .md\:hover\:text-center:hover { 50 | text-align: center; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/import-syntax.test.html: -------------------------------------------------------------------------------- 1 |

Hello world!

2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /tests/import-syntax.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('using @import instead of @tailwind', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './import-syntax.test.html')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [ 16 | function ({ addBase }) { 17 | addBase({ 18 | h1: { 19 | fontSize: '32px', 20 | }, 21 | }) 22 | }, 23 | ], 24 | } 25 | 26 | let css = ` 27 | @import "tailwindcss/base"; 28 | @import "tailwindcss/components"; 29 | @import "tailwindcss/utilities"; 30 | ` 31 | 32 | return run(css, config).then((result) => { 33 | let expectedPath = path.resolve(__dirname, './import-syntax.test.css') 34 | let expected = fs.readFileSync(expectedPath, 'utf8') 35 | 36 | expect(result.css).toMatchCss(expected) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/important-boolean.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .container { 11 | width: 100%; 12 | } 13 | @media (min-width: 640px) { 14 | .container { 15 | max-width: 640px; 16 | } 17 | } 18 | @media (min-width: 768px) { 19 | .container { 20 | max-width: 768px; 21 | } 22 | } 23 | @media (min-width: 1024px) { 24 | .container { 25 | max-width: 1024px; 26 | } 27 | } 28 | @media (min-width: 1280px) { 29 | .container { 30 | max-width: 1280px; 31 | } 32 | } 33 | @media (min-width: 1536px) { 34 | .container { 35 | max-width: 1536px; 36 | } 37 | } 38 | .btn { 39 | button: yes !important; 40 | } 41 | @font-face { 42 | font-family: Inter; 43 | } 44 | @page { 45 | margin: 1cm; 46 | } 47 | .custom-component { 48 | font-weight: 700; 49 | } 50 | .custom-important-component { 51 | text-align: center !important; 52 | } 53 | @keyframes spin { 54 | to { 55 | transform: rotate(360deg); 56 | } 57 | } 58 | .animate-spin { 59 | animation: spin 1s linear infinite !important; 60 | } 61 | .font-bold { 62 | font-weight: 700 !important; 63 | } 64 | .custom-util { 65 | button: no; 66 | } 67 | .group:hover .group-hover\:focus-within\:text-left:focus-within { 68 | text-align: left !important; 69 | } 70 | [dir='rtl'] .rtl\:active\:text-center:active { 71 | text-align: center !important; 72 | } 73 | @media (prefers-reduced-motion: no-preference) { 74 | .motion-safe\:hover\:text-center:hover { 75 | text-align: center !important; 76 | } 77 | } 78 | .dark .dark\:focus\:text-left:focus { 79 | text-align: left !important; 80 | } 81 | @media (min-width: 768px) { 82 | .md\:hover\:text-right:hover { 83 | text-align: right !important; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/important-boolean.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /tests/important-boolean.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('important boolean', () => { 11 | let config = { 12 | important: true, 13 | darkMode: 'class', 14 | purge: [path.resolve(__dirname, './important-boolean.test.html')], 15 | corePlugins: { preflight: false }, 16 | theme: {}, 17 | plugins: [ 18 | function ({ addComponents, addUtilities }) { 19 | addComponents( 20 | { 21 | '.btn': { 22 | button: 'yes', 23 | }, 24 | }, 25 | { respectImportant: true } 26 | ) 27 | addComponents( 28 | { 29 | '@font-face': { 30 | 'font-family': 'Inter', 31 | }, 32 | '@page': { 33 | margin: '1cm', 34 | }, 35 | }, 36 | { respectImportant: true } 37 | ) 38 | addUtilities( 39 | { 40 | '.custom-util': { 41 | button: 'no', 42 | }, 43 | }, 44 | { respectImportant: false } 45 | ) 46 | }, 47 | ], 48 | } 49 | 50 | let css = ` 51 | @tailwind base; 52 | @tailwind components; 53 | @layer components { 54 | .custom-component { 55 | @apply font-bold; 56 | } 57 | .custom-important-component { 58 | @apply text-center !important; 59 | } 60 | } 61 | @tailwind utilities; 62 | ` 63 | 64 | return run(css, config).then((result) => { 65 | let expectedPath = path.resolve(__dirname, './important-boolean.test.css') 66 | let expected = fs.readFileSync(expectedPath, 'utf8') 67 | 68 | expect(result.css).toMatchCss(expected) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /tests/important-modifier-prefix.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .\!tw-container { 11 | width: 100% !important; 12 | } 13 | @media (min-width: 640px) { 14 | .\!tw-container { 15 | max-width: 640px !important; 16 | } 17 | } 18 | @media (min-width: 768px) { 19 | .\!tw-container { 20 | max-width: 768px !important; 21 | } 22 | } 23 | @media (min-width: 1024px) { 24 | .\!tw-container { 25 | max-width: 1024px !important; 26 | } 27 | } 28 | @media (min-width: 1280px) { 29 | .\!tw-container { 30 | max-width: 1280px !important; 31 | } 32 | } 33 | @media (min-width: 1536px) { 34 | .\!tw-container { 35 | max-width: 1536px !important; 36 | } 37 | } 38 | .\!tw-font-bold { 39 | font-weight: 700 !important; 40 | } 41 | .hover\:\!tw-text-center:hover { 42 | text-align: center !important; 43 | } 44 | @media (min-width: 1024px) { 45 | .lg\:\!tw-opacity-50 { 46 | opacity: 0.5 !important; 47 | } 48 | } 49 | @media (min-width: 1280px) { 50 | .xl\:focus\:disabled\:\!tw-float-right:focus:disabled { 51 | float: right !important; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/important-modifier-prefix.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /tests/important-modifier-prefix.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('important modifier with prefix', () => { 11 | let config = { 12 | important: false, 13 | prefix: 'tw-', 14 | darkMode: 'class', 15 | purge: [path.resolve(__dirname, './important-modifier-prefix.test.html')], 16 | corePlugins: { preflight: false }, 17 | theme: {}, 18 | plugins: [], 19 | } 20 | 21 | let css = ` 22 | @tailwind base; 23 | @tailwind components; 24 | @tailwind utilities; 25 | ` 26 | 27 | return run(css, config).then((result) => { 28 | let expectedPath = path.resolve(__dirname, './important-modifier-prefix.test.css') 29 | let expected = fs.readFileSync(expectedPath, 'utf8') 30 | 31 | expect(result.css).toMatchCss(expected) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /tests/important-modifier.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .\!container { 11 | width: 100% !important; 12 | } 13 | @media (min-width: 640px) { 14 | .\!container { 15 | max-width: 640px !important; 16 | } 17 | } 18 | @media (min-width: 768px) { 19 | .\!container { 20 | max-width: 768px !important; 21 | } 22 | } 23 | @media (min-width: 1024px) { 24 | .\!container { 25 | max-width: 1024px !important; 26 | } 27 | } 28 | @media (min-width: 1280px) { 29 | .\!container { 30 | max-width: 1280px !important; 31 | } 32 | } 33 | @media (min-width: 1536px) { 34 | .\!container { 35 | max-width: 1536px !important; 36 | } 37 | } 38 | .\!font-bold { 39 | font-weight: 700 !important; 40 | } 41 | .hover\:\!text-center:hover { 42 | text-align: center !important; 43 | } 44 | @media (min-width: 1024px) { 45 | .lg\:\!opacity-50 { 46 | opacity: 0.5 !important; 47 | } 48 | } 49 | @media (min-width: 1280px) { 50 | .xl\:focus\:disabled\:\!float-right:focus:disabled { 51 | float: right !important; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/important-modifier.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /tests/important-modifier.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('important modifier', () => { 11 | let config = { 12 | important: false, 13 | darkMode: 'class', 14 | purge: [path.resolve(__dirname, './important-modifier.test.html')], 15 | corePlugins: { preflight: false }, 16 | theme: {}, 17 | plugins: [], 18 | } 19 | 20 | let css = ` 21 | @tailwind base; 22 | @tailwind components; 23 | @tailwind utilities; 24 | ` 25 | 26 | return run(css, config).then((result) => { 27 | let expectedPath = path.resolve(__dirname, './important-modifier.test.css') 28 | let expected = fs.readFileSync(expectedPath, 'utf8') 29 | 30 | expect(result.css).toMatchCss(expected) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /tests/important-selector.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .container { 11 | width: 100%; 12 | } 13 | @media (min-width: 640px) { 14 | .container { 15 | max-width: 640px; 16 | } 17 | } 18 | @media (min-width: 768px) { 19 | .container { 20 | max-width: 768px; 21 | } 22 | } 23 | @media (min-width: 1024px) { 24 | .container { 25 | max-width: 1024px; 26 | } 27 | } 28 | @media (min-width: 1280px) { 29 | .container { 30 | max-width: 1280px; 31 | } 32 | } 33 | @media (min-width: 1536px) { 34 | .container { 35 | max-width: 1536px; 36 | } 37 | } 38 | #app .btn { 39 | button: yes; 40 | } 41 | @font-face { 42 | font-family: Inter; 43 | } 44 | @page { 45 | margin: 1cm; 46 | } 47 | .custom-component { 48 | font-weight: 700; 49 | } 50 | .custom-important-component { 51 | text-align: center !important; 52 | } 53 | @keyframes spin { 54 | to { 55 | transform: rotate(360deg); 56 | } 57 | } 58 | #app .animate-spin { 59 | animation: spin 1s linear infinite; 60 | } 61 | #app .font-bold { 62 | font-weight: 700; 63 | } 64 | .custom-util { 65 | button: no; 66 | } 67 | #app .group:hover .group-hover\:focus-within\:text-left:focus-within { 68 | text-align: left; 69 | } 70 | #app [dir='rtl'] .rtl\:active\:text-center:active { 71 | text-align: center; 72 | } 73 | @media (prefers-reduced-motion: no-preference) { 74 | #app .motion-safe\:hover\:text-center:hover { 75 | text-align: center; 76 | } 77 | } 78 | #app .dark .dark\:focus\:text-left:focus { 79 | text-align: left; 80 | } 81 | @media (min-width: 768px) { 82 | #app .md\:hover\:text-right:hover { 83 | text-align: right; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/important-selector.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /tests/important-selector.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('important selector', () => { 11 | let config = { 12 | important: '#app', 13 | darkMode: 'class', 14 | purge: [path.resolve(__dirname, './important-selector.test.html')], 15 | corePlugins: { preflight: false }, 16 | theme: {}, 17 | plugins: [ 18 | function ({ addComponents, addUtilities }) { 19 | addComponents( 20 | { 21 | '.btn': { 22 | button: 'yes', 23 | }, 24 | }, 25 | { respectImportant: true } 26 | ) 27 | addComponents( 28 | { 29 | '@font-face': { 30 | 'font-family': 'Inter', 31 | }, 32 | '@page': { 33 | margin: '1cm', 34 | }, 35 | }, 36 | { respectImportant: true } 37 | ) 38 | addUtilities( 39 | { 40 | '.custom-util': { 41 | button: 'no', 42 | }, 43 | }, 44 | { respectImportant: false } 45 | ) 46 | }, 47 | ], 48 | } 49 | 50 | let css = ` 51 | @tailwind base; 52 | @tailwind components; 53 | @layer components { 54 | .custom-component { 55 | @apply font-bold; 56 | } 57 | .custom-important-component { 58 | @apply text-center !important; 59 | } 60 | } 61 | @tailwind utilities; 62 | ` 63 | 64 | return run(css, config).then((result) => { 65 | let expectedPath = path.resolve(__dirname, './important-selector.test.css') 66 | let expected = fs.readFileSync(expectedPath, 'utf8') 67 | 68 | expect(result.css).toMatchCss(expected) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /tests/kitchen-sink.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 | 77 | -------------------------------------------------------------------------------- /tests/kitchen-sink.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('it works', () => { 11 | let config = { 12 | darkMode: 'class', 13 | purge: [path.resolve(__dirname, './kitchen-sink.test.html')], 14 | corePlugins: { preflight: false }, 15 | theme: { 16 | extend: { 17 | screens: { 18 | portrait: { raw: '(orientation: portrait)' }, 19 | range: { min: '1280px', max: '1535px' }, 20 | multi: [{ min: '640px', max: '767px' }, { max: '868px' }], 21 | }, 22 | gradientColorStops: { 23 | foo: '#bada55', 24 | }, 25 | backgroundImage: { 26 | 'hero--home-1': "url('/images/homepage-1.jpg')", 27 | }, 28 | }, 29 | }, 30 | plugins: [ 31 | require('@tailwindcss/aspect-ratio'), 32 | function ({ addVariant }) { 33 | addVariant( 34 | 'foo', 35 | ({ container }) => { 36 | container.walkRules((rule) => { 37 | rule.selector = `.foo\\:${rule.selector.slice(1)}` 38 | rule.walkDecls((decl) => { 39 | decl.important = true 40 | }) 41 | }) 42 | }, 43 | { before: 'sm' } 44 | ) 45 | }, 46 | function ({ addUtilities, addBase, theme }) { 47 | addBase({ 48 | h1: { 49 | fontSize: theme('fontSize.2xl'), 50 | fontWeight: theme('fontWeight.bold'), 51 | '&:first-child': { 52 | marginTop: '0px', 53 | }, 54 | }, 55 | }) 56 | addUtilities( 57 | { 58 | '.filter-none': { 59 | filter: 'none', 60 | }, 61 | '.filter-grayscale': { 62 | filter: 'grayscale(100%)', 63 | }, 64 | }, 65 | ['responsive', 'hover'] 66 | ) 67 | }, 68 | ], 69 | } 70 | 71 | let css = ` 72 | @layer utilities { 73 | .custom-util { 74 | background: #abcdef; 75 | } 76 | * { 77 | margin: 10px; 78 | } 79 | } 80 | @layer components { 81 | .test-apply-font-variant { 82 | @apply ordinal tabular-nums; 83 | } 84 | .custom-component { 85 | background: #123456; 86 | } 87 | * { 88 | padding: 5px; 89 | } 90 | .foo .bg-black { 91 | appearance: none; 92 | } 93 | } 94 | @layer base { 95 | div { 96 | background: #654321; 97 | } 98 | } 99 | .theme-test { 100 | font-family: theme('fontFamily.sans'); 101 | color: theme('colors.blue.500'); 102 | } 103 | @screen lg { 104 | .screen-test { 105 | color: purple; 106 | } 107 | } 108 | .apply-1 { 109 | @apply mt-6; 110 | } 111 | .apply-2 { 112 | @apply mt-6; 113 | } 114 | .apply-test { 115 | @apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200; 116 | } 117 | .apply-components { 118 | @apply container mx-auto; 119 | } 120 | .drop-empty-rules { 121 | @apply hover:font-bold; 122 | } 123 | .apply-group { 124 | @apply group-hover:font-bold; 125 | } 126 | .apply-dark-mode { 127 | @apply dark:font-bold; 128 | } 129 | .apply-with-existing:hover { 130 | @apply font-normal sm:bg-green-500; 131 | } 132 | .multiple, .selectors { 133 | @apply font-bold group-hover:font-normal; 134 | } 135 | .list { 136 | @apply space-x-4; 137 | } 138 | .nested { 139 | .example { 140 | @apply font-bold hover:font-normal; 141 | } 142 | } 143 | .apply-order-a { 144 | @apply m-5 mt-6; 145 | } 146 | .apply-order-b { 147 | @apply mt-6 m-5; 148 | } 149 | .apply-dark-group-example-a { 150 | @apply dark:group-hover:bg-green-500; 151 | } 152 | .crazy-example { 153 | @apply sm:motion-safe:group-active:focus:opacity-10; 154 | } 155 | @tailwind base; 156 | @tailwind components; 157 | @tailwind utilities; 158 | ` 159 | 160 | return run(css, config).then((result) => { 161 | let expectedPath = path.resolve(__dirname, './kitchen-sink.test.css') 162 | let expected = fs.readFileSync(expectedPath, 'utf8') 163 | 164 | expect(result.css).toMatchCss(expected) 165 | }) 166 | }) 167 | -------------------------------------------------------------------------------- /tests/modify-selectors.test.css: -------------------------------------------------------------------------------- 1 | .markdown > p { 2 | margin-top: 12px; 3 | } 4 | .font-bold { 5 | font-weight: 700; 6 | } 7 | .foo .foo\:markdown > p { 8 | margin-top: 12px; 9 | } 10 | .foo .foo\:font-bold { 11 | font-weight: 700; 12 | } 13 | .foo .foo\:visited\:markdown:visited > p { 14 | margin-top: 12px; 15 | } 16 | .foo .foo\:hover\:font-bold:hover { 17 | font-weight: 700; 18 | } 19 | @media (min-width: 640px) { 20 | .foo .sm\:foo\:font-bold { 21 | font-weight: 700; 22 | } 23 | } 24 | @media (min-width: 768px) { 25 | .foo .md\:foo\:focus\:font-bold:focus { 26 | font-weight: 700; 27 | } 28 | } 29 | @media (min-width: 1024px) { 30 | .foo .lg\:foo\:disabled\:markdown:disabled > p { 31 | margin-top: 12px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/modify-selectors.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |

Lorem ipsum dolor sit amet...

8 |
9 |
10 |

Lorem ipsum dolor sit amet...

11 |
12 |
13 |

Lorem ipsum dolor sit amet...

14 |
15 |
16 |

Lorem ipsum dolor sit amet...

17 |
18 | -------------------------------------------------------------------------------- /tests/modify-selectors.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | const selectorParser = require('postcss-selector-parser') 6 | 7 | function run(input, config = {}) { 8 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 9 | } 10 | 11 | test('modify selectors', () => { 12 | let config = { 13 | darkMode: 'class', 14 | purge: [path.resolve(__dirname, './modify-selectors.test.html')], 15 | corePlugins: { preflight: false }, 16 | theme: {}, 17 | plugins: [ 18 | function ({ addVariant, e }) { 19 | addVariant('foo', ({ modifySelectors, separator }) => { 20 | modifySelectors(({ selector }) => { 21 | return selectorParser((selectors) => { 22 | selectors.walkClasses((classNode) => { 23 | classNode.value = `foo${separator}${classNode.value}` 24 | classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) 25 | }) 26 | }).processSync(selector) 27 | }) 28 | }) 29 | }, 30 | ], 31 | } 32 | 33 | let css = ` 34 | @tailwind components; 35 | @tailwind utilities; 36 | 37 | @layer components { 38 | .markdown > p { 39 | margin-top: 12px; 40 | } 41 | } 42 | ` 43 | 44 | return run(css, config).then((result) => { 45 | let expectedPath = path.resolve(__dirname, './modify-selectors.test.css') 46 | let expected = fs.readFileSync(expectedPath, 'utf8') 47 | 48 | expect(result.css).toMatchCss(expected) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /tests/mutable.test.css: -------------------------------------------------------------------------------- 1 | .bg-foo { 2 | background-image: url("./foo.png"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/mutable.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/mutable.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function pluginThatMutatesRules() { 7 | return (root) => { 8 | root.walkRules((rule) => { 9 | rule.nodes 10 | .filter((node) => node.prop === 'background-image') 11 | .forEach((node) => { 12 | node.value = 'url("./bar.png")' 13 | }) 14 | 15 | return rule 16 | }) 17 | } 18 | } 19 | 20 | function run(input, config = {}) { 21 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 22 | } 23 | 24 | test.only('plugins mutating rules after tailwind doesnt break it', async () => { 25 | let config = { 26 | purge: [path.resolve(__dirname, './mutable.test.html')], 27 | theme: { 28 | backgroundImage: { 29 | foo: 'url("./foo.png")', 30 | }, 31 | }, 32 | plugins: [], 33 | } 34 | 35 | let css = `@tailwind utilities;` 36 | 37 | function checkResult(result) { 38 | let expectedPath = path.resolve(__dirname, './mutable.test.css') 39 | let expected = fs.readFileSync(expectedPath, 'utf8') 40 | 41 | expect(result.css).toMatchCss(expected) 42 | } 43 | 44 | // Verify the first run produces the expected result 45 | let firstRun = await run(css, config) 46 | checkResult(firstRun) 47 | 48 | // Outside of the context of tailwind jit more postcss plugins may operate on the AST: 49 | // In this case we have a plugin that mutates rules directly 50 | await postcss([pluginThatMutatesRules()]).process(firstRun, { from: path.resolve(__filename) }) 51 | 52 | // Verify subsequent runs don't produce mutated rules 53 | let secondRun = await run(css, config) 54 | checkResult(secondRun) 55 | }) 56 | -------------------------------------------------------------------------------- /tests/prefix.fn.test.css: -------------------------------------------------------------------------------- 1 | .tw-ml-1 { 2 | margin-left: 0.25rem; 3 | } 4 | .flex { 5 | display: flex; 6 | } 7 | .tw-align-bottom { 8 | vertical-align: bottom 9 | } 10 | -------------------------------------------------------------------------------- /tests/prefix.fn.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /tests/prefix.fn.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('prefix fn', () => { 11 | let config = { 12 | prefix(selector) { 13 | if (['.align-bottom', '.ml'].some(prefix => selector.startsWith(prefix))) { 14 | return 'tw-'; 15 | } 16 | 17 | return ''; 18 | }, 19 | purge: [path.resolve(__dirname, './prefix.fn.test.html')], 20 | corePlugins: { preflight: false }, 21 | theme: {}, 22 | } 23 | 24 | let css = ` 25 | @tailwind utilities; 26 | ` 27 | 28 | return run(css, config).then((result) => { 29 | let expectedPath = path.resolve(__dirname, './prefix.fn.test.css') 30 | let expected = fs.readFileSync(expectedPath, 'utf8') 31 | 32 | expect(result.css).toMatchCss(expected) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /tests/prefix.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .tw-container { 11 | width: 100%; 12 | } 13 | @media (min-width: 640px) { 14 | .tw-container { 15 | max-width: 640px; 16 | } 17 | } 18 | @media (min-width: 768px) { 19 | .tw-container { 20 | max-width: 768px; 21 | } 22 | } 23 | @media (min-width: 1024px) { 24 | .tw-container { 25 | max-width: 1024px; 26 | } 27 | } 28 | @media (min-width: 1280px) { 29 | .tw-container { 30 | max-width: 1280px; 31 | } 32 | } 33 | @media (min-width: 1536px) { 34 | .tw-container { 35 | max-width: 1536px; 36 | } 37 | } 38 | .tw-btn-prefix { 39 | button: yes; 40 | } 41 | .btn-no-prefix { 42 | button: yes; 43 | } 44 | .custom-component { 45 | font-weight: 700; 46 | } 47 | .tw-dark .tw-group:hover .custom-component { 48 | font-weight: 400; 49 | } 50 | .tw--ml-4 { 51 | margin-left: -1rem; 52 | } 53 | .tw-font-bold { 54 | font-weight: 700; 55 | } 56 | .tw-custom-util-prefix { 57 | button: no; 58 | } 59 | .custom-util-no-prefix { 60 | button: no; 61 | } 62 | .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { 63 | text-align: left; 64 | } 65 | [dir='rtl'] .rtl\:active\:tw-text-center:active { 66 | text-align: center; 67 | } 68 | @media (prefers-reduced-motion: no-preference) { 69 | .motion-safe\:hover\:tw-text-center:hover { 70 | text-align: center; 71 | } 72 | } 73 | .tw-dark .dark\:focus\:tw-text-left:focus { 74 | text-align: left; 75 | } 76 | @media (min-width: 768px) { 77 | .md\:tw--ml-5 { 78 | margin-left: -1.25rem; 79 | } 80 | .md\:hover\:tw--ml-6:hover { 81 | margin-left: -1.5rem; 82 | } 83 | .md\:hover\:tw-text-right:hover { 84 | text-align: right; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/prefix.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /tests/prefix.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('prefix', () => { 11 | let config = { 12 | prefix: 'tw-', 13 | darkMode: 'class', 14 | purge: [path.resolve(__dirname, './prefix.test.html')], 15 | corePlugins: { preflight: false }, 16 | theme: {}, 17 | plugins: [ 18 | function ({ addComponents, addUtilities }) { 19 | addComponents({ 20 | '.btn-prefix': { 21 | button: 'yes', 22 | }, 23 | }) 24 | addComponents( 25 | { 26 | '.btn-no-prefix': { 27 | button: 'yes', 28 | }, 29 | }, 30 | { respectPrefix: false } 31 | ) 32 | addUtilities({ 33 | '.custom-util-prefix': { 34 | button: 'no', 35 | }, 36 | }) 37 | addUtilities( 38 | { 39 | '.custom-util-no-prefix': { 40 | button: 'no', 41 | }, 42 | }, 43 | { respectPrefix: false } 44 | ) 45 | }, 46 | ], 47 | } 48 | 49 | let css = ` 50 | @tailwind base; 51 | @tailwind components; 52 | @layer components { 53 | .custom-component { 54 | @apply tw-font-bold dark:group-hover:tw-font-normal; 55 | } 56 | } 57 | @tailwind utilities; 58 | @layer utilites { 59 | .custom-utility { 60 | foo: bar; 61 | } 62 | } 63 | ` 64 | 65 | return run(css, config).then((result) => { 66 | let expectedPath = path.resolve(__dirname, './prefix.test.css') 67 | let expected = fs.readFileSync(expectedPath, 'utf8') 68 | 69 | expect(result.css).toMatchCss(expected) 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /tests/responsive-and-variants-atrules.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | .responsive-in-components { 11 | color: blue; 12 | } 13 | .variants-in-components { 14 | color: red; 15 | } 16 | .both-in-components { 17 | color: green; 18 | } 19 | .responsive-in-utilities { 20 | color: blue; 21 | } 22 | .variants-in-utilities { 23 | color: red; 24 | } 25 | .both-in-utilities { 26 | color: green; 27 | } 28 | .responsive-at-root { 29 | color: white; 30 | } 31 | .variants-at-root { 32 | color: orange; 33 | } 34 | .both-at-root { 35 | color: pink; 36 | } 37 | @media (min-width: 768px) { 38 | .md\:focus\:responsive-in-components:focus { 39 | color: blue; 40 | } 41 | .md\:focus\:variants-in-components:focus { 42 | color: red; 43 | } 44 | .md\:focus\:both-in-components:focus { 45 | color: green; 46 | } 47 | .md\:focus\:responsive-in-utilities:focus { 48 | color: blue; 49 | } 50 | .md\:focus\:variants-in-utilities:focus { 51 | color: red; 52 | } 53 | .md\:focus\:both-in-utilities:focus { 54 | color: green; 55 | } 56 | .md\:focus\:responsive-at-root:focus { 57 | color: white; 58 | } 59 | .md\:focus\:variants-at-root:focus { 60 | color: orange; 61 | } 62 | .md\:focus\:both-at-root:focus { 63 | color: pink; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/responsive-and-variants-atrules.test.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /tests/responsive-and-variants-atrules.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('responsive and variants atrules', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './responsive-and-variants-atrules.test.html')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [], 16 | } 17 | 18 | let css = ` 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | 23 | @layer utilities { 24 | @responsive { 25 | .responsive-in-utilities { 26 | color: blue; 27 | } 28 | } 29 | @variants { 30 | .variants-in-utilities { 31 | color: red; 32 | } 33 | } 34 | @responsive { 35 | @variants { 36 | .both-in-utilities { 37 | color: green; 38 | } 39 | } 40 | } 41 | } 42 | 43 | @responsive { 44 | .responsive-at-root { 45 | color: white; 46 | } 47 | } 48 | @variants { 49 | .variants-at-root { 50 | color: orange; 51 | } 52 | } 53 | @responsive { 54 | @variants { 55 | .both-at-root { 56 | color: pink; 57 | } 58 | } 59 | } 60 | 61 | @layer components { 62 | @responsive { 63 | .responsive-in-components { 64 | color: blue; 65 | } 66 | } 67 | @variants { 68 | .variants-in-components { 69 | color: red; 70 | } 71 | } 72 | @responsive { 73 | @variants { 74 | .both-in-components { 75 | color: green; 76 | } 77 | } 78 | } 79 | } 80 | ` 81 | 82 | return run(css, config).then((result) => { 83 | let expectedPath = path.resolve(__dirname, './responsive-and-variants-atrules.test.css') 84 | let expected = fs.readFileSync(expectedPath, 'utf8') 85 | 86 | expect(result.css).toMatchCss(expected) 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /tests/svelte-syntax.test.css: -------------------------------------------------------------------------------- 1 | * { 2 | --tw-shadow: 0 0 #0000; 3 | --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); 4 | --tw-ring-offset-width: 0px; 5 | --tw-ring-offset-color: #fff; 6 | --tw-ring-color: rgba(59, 130, 246, 0.5); 7 | --tw-ring-offset-shadow: 0 0 #0000; 8 | --tw-ring-shadow: 0 0 #0000; 9 | } 10 | @media (min-width: 1024px) { 11 | .lg\:hover\:bg-blue-500:hover { 12 | --tw-bg-opacity: 1; 13 | background-color: rgba(59, 130, 246, var(--tw-bg-opacity)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/svelte-syntax.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('basic usage', () => { 11 | let config = { 12 | purge: [path.resolve(__dirname, './svelte-syntax.test.svelte')], 13 | corePlugins: { preflight: false }, 14 | theme: {}, 15 | plugins: [], 16 | } 17 | 18 | let css = ` 19 | @tailwind base; 20 | @tailwind components; 21 | @tailwind utilities; 22 | ` 23 | 24 | return run(css, config).then((result) => { 25 | let expectedPath = path.resolve(__dirname, './svelte-syntax.test.css') 26 | let expected = fs.readFileSync(expectedPath, 'utf8') 27 | 28 | expect(result.css).toMatchCss(expected) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/svelte-syntax.test.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/variants.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 |
44 |
45 | 46 | 47 |
48 |
49 | 50 | 51 |
52 | 53 | 54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 |
62 |
63 |
64 |
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /tests/variants.test.js: -------------------------------------------------------------------------------- 1 | const postcss = require('postcss') 2 | const tailwind = require('../src/index.js') 3 | const fs = require('fs') 4 | const path = require('path') 5 | 6 | function run(input, config = {}) { 7 | return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) }) 8 | } 9 | 10 | test('variants', () => { 11 | let config = { 12 | darkMode: 'class', 13 | purge: [path.resolve(__dirname, './variants.test.html')], 14 | corePlugins: { preflight: false }, 15 | theme: {}, 16 | plugins: [], 17 | } 18 | 19 | let css = ` 20 | @tailwind base; 21 | @tailwind components; 22 | @tailwind utilities; 23 | ` 24 | 25 | return run(css, config).then((result) => { 26 | let expectedPath = path.resolve(__dirname, './variants.test.css') 27 | let expected = fs.readFileSync(expectedPath, 'utf8') 28 | 29 | expect(result.css).toMatchCss(expected) 30 | }) 31 | }) 32 | --------------------------------------------------------------------------------