├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── ---bug-report.md │ ├── ---support-question.md │ └── --feature-request.md ├── dependabot.yml └── workflows │ ├── build.yml │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .run └── tailwindcss-variables-test.run.xml ├── LICENSE ├── README.md ├── README.tr.md ├── __tests__ ├── basic-usage.test.html ├── basic-usage.test.js ├── color-variable-helper.test.html ├── color-variable-helper.test.js ├── color-variable-helper2.test.html ├── css-selectors.test.html ├── css-selectors.test.js ├── dark-mode-to-root.test.html ├── dark-mode.test.html ├── dark-mode.test.js ├── extend-colors.test.html ├── extend-colors.test.js ├── fallback.test.css ├── fallback.test.html ├── fallback.test.js ├── force-rgb.test.html ├── force-rgb.test.js ├── format-variables.test.html ├── format-variables.test.js ├── issues.test.html ├── issues.test.js ├── nested-variables.test.html ├── nested-variables.test.js ├── plugin-api.test.html ├── plugin-api.test.js ├── readme.test.html ├── readme.test.js ├── test.stub ├── to-base.test.html ├── to-base.test.js ├── use-host.test.html ├── use-host.test.js ├── util │ └── _utils.js ├── variable-prefix.test.html └── variable-prefix.test.js ├── api.js ├── colorVariable.js ├── examples ├── .npmignore ├── api-examples │ ├── advanced │ │ ├── components.js │ │ ├── index.js │ │ └── themes.js │ ├── readme-source │ │ ├── components.js │ │ ├── index.html │ │ ├── index.js │ │ ├── tailwind.config.js │ │ └── themes.js │ ├── simple │ │ └── index.js │ ├── with-components-null-selector │ │ ├── components.js │ │ └── index.js │ ├── with-components │ │ ├── components.js │ │ └── index.js │ └── with-themes │ │ ├── index.js │ │ └── themes.js ├── color-variable-helper │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── dark-custom-selector │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── dark-with-class-to-root │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── dark-with-class │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── dark-with-media │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── prefix │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── simple │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css └── use-host │ ├── clean.css │ ├── image.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── tailwind.config.js │ └── tailwind.css ├── package-lock.json ├── package.json ├── scripts └── build.js └── src ├── helpers.js ├── index.js ├── pluginApi.js └── utils.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | max_line_length = 120 11 | 12 | [*.php] 13 | indent_size = 4 14 | 15 | [*.md] 16 | trim_trailing_whitespace = true 17 | 18 | [*.test.js] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /__tests__/util/_utils.js 2 | *.stub 3 | .run 4 | *.md 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | }, 5 | "parserOptions": { 6 | "ecmaVersion": 2020, 7 | "sourceType": "module" 8 | }, 9 | "extends": [ 10 | "prettier" 11 | ], 12 | "plugins": [ 13 | "prettier" 14 | ], 15 | "rules": { 16 | "camelcase": [ 17 | "error", 18 | { 19 | "allow": [ 20 | "^unstable_" 21 | ] 22 | } 23 | ], 24 | "no-unused-vars": [ 25 | 2, 26 | { 27 | "args": "none", 28 | "argsIgnorePattern": "^_" 29 | } 30 | ], 31 | "no-warning-comments": 0, 32 | "prettier/prettier": [ 33 | "error", 34 | { 35 | "semi": false, 36 | "singleQuote": true, 37 | "printWidth": 120, 38 | "tabWidth": 2, 39 | "useTabs": false, 40 | "trailingComma": "es5", 41 | "bracketSpacing": true, 42 | "parser": "flow", 43 | "overrides": [ 44 | { 45 | "files": [ 46 | "**/*.css", 47 | "**/*.scss", 48 | "**/*.html" 49 | ], 50 | "options": { 51 | "singleQuote": false 52 | } 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mertasan 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F4CC Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Versions: 11 | - Package Version: #.#.# 12 | - Tailwindcss Version: #.#.# 13 | 14 | ### Description: 15 | 16 | 17 | 18 | ### Steps To Reproduce: 19 | 20 | - … 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---support-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F914 Support Question" 3 | about: I need assistance or clarification on usage of this library 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Versions: 11 | - Package Version: #.#.# 12 | - Tailwindcss Version: #.#.# 13 | 14 | ### Question: 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F389Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature request 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Summary 11 | 12 | 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "03:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - 'examples/**' 8 | pull_request: 9 | branches: [ master ] 10 | release: 11 | types: [ published, edited ] 12 | 13 | jobs: 14 | build: 15 | if: ${{ github.event_name != 'pull_request' || (github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true) }} 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [16] 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | 25 | - name: Use Node ${{ matrix.node-version }} 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | 30 | - name: Use cached node_modules 31 | id: cache-build 32 | uses: actions/cache@v3 33 | with: 34 | path: node_modules 35 | key: nodeModules-${{ hashFiles('**/package-lock.json') }}-${{ matrix.node-version }}-build 36 | restore-keys: | 37 | nodeModules- 38 | - name: Install dependencies 39 | if: steps.cache-build.outputs.cache-hit != 'true' 40 | run: npm install 41 | env: 42 | CI: true 43 | 44 | - name: Building Examples 45 | run: npm run build 46 | - name: Clean CSS styles of the Examples are building 47 | run: npm run build:clean 48 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: npm-publish 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published, edited] 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | node-version: [16] 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | registry-url: 'https://registry.npmjs.org' 24 | scope: '@mertasan' 25 | 26 | - name: Use cached node_modules 27 | id: cache-publish 28 | uses: actions/cache@v3 29 | with: 30 | path: node_modules 31 | key: nodeModules-${{ hashFiles('**/package-lock.json') }}-${{ matrix.node-version }}-publish 32 | restore-keys: | 33 | nodeModules- 34 | - name: Install dependencies 35 | if: steps.cache-publish.outputs.cache-hit != 'true' 36 | run: npm install 37 | env: 38 | CI: true 39 | 40 | - name: Test 41 | run: npm run test 42 | env: 43 | CI: true 44 | 45 | - name: Publish 46 | run: npm publish 47 | env: 48 | CI: true 49 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 50 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - "**" 7 | paths-ignore: 8 | - '**.md' 9 | pull_request: 10 | types: [ready_for_review, synchronize, opened] 11 | schedule: 12 | - cron: '0 0 * * *' 13 | 14 | jobs: 15 | tests: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | node-version: [16] 20 | 21 | steps: 22 | - name: Use Node ${{ matrix.node-version }} 23 | uses: actions/checkout@v3 24 | - name: Setup node ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | 30 | - name: Install dependencies 31 | if: steps.npm-cache.outputs.cache-hit != 'true' 32 | run: npm install 33 | env: 34 | CI: true 35 | 36 | - name: Lint 37 | run: npm run lint 38 | env: 39 | CI: true 40 | 41 | - name: Tests 42 | run: npm run test -- --coverage 43 | env: 44 | CI: true 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | **/*/package-lock.json 3 | yarn.lock 4 | coverage/ 5 | .DS_Store 6 | .idea 7 | cache/ 8 | *.log 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /coverage 3 | /examples 4 | yarn.lock 5 | yarn-error.log 6 | .DS_Store 7 | .idea 8 | .prettierignore 9 | .run 10 | cache/ 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | coverage 8 | bower_components 9 | package.json 10 | package-lock.json 11 | node_modules/ 12 | .npm 13 | .idea/ 14 | .DS_Store 15 | __tests__/* 16 | !__tests__/util/* 17 | examples/* 18 | !examples/**/*.config.js 19 | .run 20 | .editorconfig 21 | cache/ 22 | .github/ 23 | .eslintrc.json 24 | *.md 25 | .prettierrc 26 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true, 9 | "parser": "flow", 10 | "overrides": [ 11 | { 12 | "files": [ 13 | "**/*.css", 14 | "**/*.scss", 15 | "**/*.html" 16 | ], 17 | "options": { 18 | "singleQuote": false 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.run/tailwindcss-variables-test.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mert Aşan 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 | -------------------------------------------------------------------------------- /__tests__/basic-usage.test.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/basic-usage.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('basic usage', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | colors: { 13 | black: 'rgb(0, 0, 0)', 14 | white: '#ffffff', 15 | }, 16 | 17 | sizes: { 18 | small: '10px', 19 | medium: '2rem', 20 | large: '100%', 21 | }, 22 | }, 23 | 24 | '.container': { 25 | colors: { 26 | primary: 'red', 27 | secondary: 'var(--colors-primary)', 28 | }, 29 | }, 30 | }, 31 | }, 32 | 33 | plugins: [tailwindcssVariables], 34 | }) 35 | ).toMatchInlineSnapshot(` 36 | " 37 | 38 | 39 | + :root { 40 | + --colors-black: rgb(0, 0, 0); 41 | + --colors-white: #ffffff; 42 | + --sizes-small: 10px; 43 | + --sizes-medium: 2rem; 44 | + --sizes-large: 100% 45 | + } 46 | + .container { 47 | + --colors-primary: red; 48 | + --colors-secondary: var(--colors-primary) 49 | + } 50 | 51 | " 52 | `) 53 | }) 54 | -------------------------------------------------------------------------------- /__tests__/color-variable-helper.test.html: -------------------------------------------------------------------------------- 1 | tailwindcss-variables 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | tailwindcss-variables 5 | tailwindcss-variables 6 | tailwindcss-variables 7 | tailwindcss-variables 8 | tailwindcss-variables 9 | tailwindcss-variables 10 | tailwindcss-variables 11 | 12 | tailwindcss-variables 13 | tailwindcss-variables 14 | tailwindcss-variables 15 | 16 | tailwindcss-variables 17 | tailwindcss-variables 18 | tailwindcss-variables 19 | -------------------------------------------------------------------------------- /__tests__/color-variable-helper.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | const colorVariable = require('../colorVariable') 4 | 5 | test('colorVariable helper', async () => { 6 | expect( 7 | await utils.diffOnly({ 8 | corePlugins: ['textColor', 'textOpacity', 'backgroundColor', 'backgroundOpacity'], 9 | content: [utils.content()], 10 | darkMode: false, 11 | theme: { 12 | screens: false, 13 | colors: { 14 | primary: colorVariable('--colors-primary'), // HEX (3 digits) 15 | secondary: colorVariable('var(--colors-secondary)'), // HEX (6 digits) 16 | white: '#ffffff', // no variable 17 | blue: colorVariable('var(--colors-blue)'), // RGB 18 | yellow: { 19 | 400: colorVariable('var(--colors-yellow-400)'), // RGB 20 | DEFAULT: colorVariable('var(--colors-yellow)'), // RGB 21 | }, 22 | red: { 23 | 400: colorVariable('var(--colors-red-400)'), // RGBA 24 | 500: colorVariable('var(--colors-red-500)'), // RGBA 25 | 600: 'var(--colors-red-500)', // RGBA (without using colorVariable() helper) 26 | }, 27 | gray: 'var(--colors-gray)', // HEX (6 digits) (without using colorVariable() helper) 28 | green: 'var(--colors-green)', // RGB (without using colorVariable() helper) 29 | }, 30 | variables: { 31 | DEFAULT: { 32 | colors: { 33 | primary: '#ff0', 34 | secondary: '#000000', 35 | gray: '#6B7280', 36 | blue: 'rgb(0,0,254)', 37 | red: { 38 | 400: 'rgba(254,0,0,0.5)', 39 | 500: 'rgba(254,0,0,1)', 40 | }, 41 | 42 | green: 'rgb(0,255,0)', 43 | yellow: { 44 | 400: 'rgb(255,255,0)', 45 | DEFAULT: 'rgb(255,255,0)', 46 | }, 47 | }, 48 | 49 | sizes: { 50 | small: '10px', 51 | medium: '2rem', 52 | large: '100%', 53 | }, 54 | }, 55 | }, 56 | }, 57 | 58 | plugins: [ 59 | tailwindcssVariables({ 60 | colorVariables: true, 61 | }), 62 | ], 63 | }) 64 | ).toMatchInlineSnapshot(` 65 | " 66 | 67 | 68 | + :root { 69 | + --colors-primary: #ff0; 70 | + --colors-secondary: #000000; 71 | + --colors-gray: #6B7280; 72 | + --colors-blue: rgb(0,0,254); 73 | + --colors-red-400: rgba(254,0,0,0.5); 74 | + --colors-red-500: rgba(254,0,0,1); 75 | + --colors-red-400-rgb: 254,0,0; 76 | + --colors-red-500-rgb: 254,0,0; 77 | + --colors-green: rgb(0,255,0); 78 | + --colors-yellow-400: rgb(255,255,0); 79 | + --colors-yellow: rgb(255,255,0); 80 | + --colors-yellow-400-rgb: 255,255,0; 81 | + --colors-yellow-rgb: 255,255,0; 82 | + --colors-primary-rgb: 255,255,0; 83 | + --colors-secondary-rgb: 0,0,0; 84 | + --colors-gray-rgb: 107,114,128; 85 | + --colors-blue-rgb: 0,0,254; 86 | + --colors-green-rgb: 0,255,0; 87 | + --sizes-small: 10px; 88 | + --sizes-medium: 2rem; 89 | + --sizes-large: 100% 90 | + } 91 | + .bg-gray { 92 | + background-color: var(--colors-gray) 93 | + } 94 | + .bg-green { 95 | + background-color: var(--colors-green) 96 | + } 97 | + .bg-red-400 { 98 | + --tw-bg-opacity: 1; 99 | + background-color: rgba(var(--colors-red-400-rgb), var(--tw-bg-opacity)) 100 | + } 101 | + .bg-red-500 { 102 | + --tw-bg-opacity: 1; 103 | + background-color: rgba(var(--colors-red-500-rgb), var(--tw-bg-opacity)) 104 | + } 105 | + .bg-red-600 { 106 | + background-color: var(--colors-red-500) 107 | + } 108 | + .bg-secondary { 109 | + --tw-bg-opacity: 1; 110 | + background-color: rgba(var(--colors-secondary-rgb), var(--tw-bg-opacity)) 111 | + } 112 | + .bg-white { 113 | + --tw-bg-opacity: 1; 114 | + background-color: rgb(255 255 255 / var(--tw-bg-opacity)) 115 | + } 116 | + .bg-yellow { 117 | + --tw-bg-opacity: 1; 118 | + background-color: rgba(var(--colors-yellow-rgb), var(--tw-bg-opacity)) 119 | + } 120 | + .bg-opacity-50 { 121 | + --tw-bg-opacity: 0.5 122 | + } 123 | + .text-blue { 124 | + --tw-text-opacity: 1; 125 | + color: rgba(var(--colors-blue-rgb), var(--tw-text-opacity)) 126 | + } 127 | + .text-primary { 128 | + --tw-text-opacity: 1; 129 | + color: rgba(var(--colors-primary-rgb), var(--tw-text-opacity)) 130 | + } 131 | + .text-opacity-50 { 132 | + --tw-text-opacity: 0.5 133 | + } 134 | 135 | " 136 | `) 137 | }) 138 | 139 | test('colorVariable - background and text color', async () => { 140 | expect( 141 | await utils.diffOnly({ 142 | corePlugins: ['textColor', 'textOpacity', 'backgroundColor', 'backgroundOpacity'], 143 | content: [utils.content()], 144 | darkMode: false, 145 | theme: { 146 | screens: false, 147 | colors: { 148 | indigo: { 149 | 400: colorVariable('var(--colors-indigo-400)', true), // RGBA 150 | 500: colorVariable('var(--colors-indigo-500)', true), // RGBA 151 | 600: colorVariable('var(--colors-indigo-600)', true), // HEX 152 | }, 153 | }, 154 | 155 | variables: { 156 | DEFAULT: { 157 | colors: { 158 | indigo: { 159 | 400: 'rgba(254,0,0,1)', 160 | 500: 'rgba(254,0,0,0.5)', 161 | 600: '#a20606', 162 | }, 163 | }, 164 | }, 165 | }, 166 | 167 | plugins: [ 168 | tailwindcssVariables({ 169 | colorVariables: true, 170 | forceRGB: true, 171 | }), 172 | ], 173 | }, 174 | }) 175 | ).toMatchInlineSnapshot(` 176 | " 177 | 178 | 179 | + .bg-indigo-400 { 180 | + --tw-bg-opacity: 1; 181 | + background-color: rgba(var(--colors-indigo-400), var(--tw-bg-opacity)) 182 | + } 183 | + .bg-indigo-500 { 184 | + --tw-bg-opacity: 1; 185 | + background-color: rgba(var(--colors-indigo-500), var(--tw-bg-opacity)) 186 | + } 187 | + .bg-indigo-600 { 188 | + --tw-bg-opacity: 1; 189 | + background-color: rgba(var(--colors-indigo-600), var(--tw-bg-opacity)) 190 | + } 191 | + .bg-opacity-50 { 192 | + --tw-bg-opacity: 0.5 193 | + } 194 | + .text-indigo-400 { 195 | + --tw-text-opacity: 1; 196 | + color: rgba(var(--colors-indigo-400), var(--tw-text-opacity)) 197 | + } 198 | + .text-indigo-500 { 199 | + --tw-text-opacity: 1; 200 | + color: rgba(var(--colors-indigo-500), var(--tw-text-opacity)) 201 | + } 202 | + .text-indigo-600 { 203 | + --tw-text-opacity: 1; 204 | + color: rgba(var(--colors-indigo-600), var(--tw-text-opacity)) 205 | + } 206 | + .text-opacity-50 { 207 | + --tw-text-opacity: 0.5 208 | + } 209 | 210 | " 211 | `) 212 | }) 213 | 214 | /** 215 | * a --tw-bg-opacity must be added to the colors even if the bg-opacity-100 class is not present. 216 | */ 217 | test('colorVariable - background and text color 2', async () => { 218 | expect( 219 | await utils.diffOnly({ 220 | corePlugins: ['textColor', 'textOpacity', 'backgroundColor', 'backgroundOpacity'], 221 | content: [utils.content('color-variable-helper2')], 222 | 223 | darkMode: false, 224 | theme: { 225 | screens: false, 226 | colors: { 227 | indigo: { 228 | 400: colorVariable('var(--colors-indigo-400)', true), // RGBA 229 | 500: colorVariable('var(--colors-indigo-500)', true), // RGBA 230 | 600: colorVariable('var(--colors-indigo-600)', true), // HEX 231 | }, 232 | }, 233 | 234 | variables: { 235 | DEFAULT: { 236 | colors: { 237 | indigo: { 238 | 400: 'rgba(254,0,0,1)', 239 | 500: 'rgba(254,0,0,0.5)', 240 | 600: '#a20606', 241 | }, 242 | }, 243 | }, 244 | }, 245 | 246 | plugins: [ 247 | tailwindcssVariables({ 248 | colorVariables: true, 249 | forceRGB: true, 250 | }), 251 | ], 252 | }, 253 | }) 254 | ).toMatchInlineSnapshot(` 255 | " 256 | 257 | 258 | + .bg-indigo-400 { 259 | + --tw-bg-opacity: 1; 260 | + background-color: rgba(var(--colors-indigo-400), var(--tw-bg-opacity)) 261 | + } 262 | + .bg-indigo-500 { 263 | + --tw-bg-opacity: 1; 264 | + background-color: rgba(var(--colors-indigo-500), var(--tw-bg-opacity)) 265 | + } 266 | + .bg-indigo-600 { 267 | + --tw-bg-opacity: 1; 268 | + background-color: rgba(var(--colors-indigo-600), var(--tw-bg-opacity)) 269 | + } 270 | + .text-indigo-400 { 271 | + --tw-text-opacity: 1; 272 | + color: rgba(var(--colors-indigo-400), var(--tw-text-opacity)) 273 | + } 274 | + .text-indigo-500 { 275 | + --tw-text-opacity: 1; 276 | + color: rgba(var(--colors-indigo-500), var(--tw-text-opacity)) 277 | + } 278 | + .text-indigo-600 { 279 | + --tw-text-opacity: 1; 280 | + color: rgba(var(--colors-indigo-600), var(--tw-text-opacity)) 281 | + } 282 | 283 | " 284 | `) 285 | }) 286 | -------------------------------------------------------------------------------- /__tests__/color-variable-helper2.test.html: -------------------------------------------------------------------------------- 1 | tailwindcss-variables 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | 5 | tailwindcss-variables 6 | tailwindcss-variables 7 | tailwindcss-variables 8 | -------------------------------------------------------------------------------- /__tests__/css-selectors.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /__tests__/css-selectors.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('css selectors', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | '#app': { 12 | colors: { 13 | black: 'rgb(0, 0, 0)', 14 | white: '#ffffff', 15 | }, 16 | }, 17 | 18 | 'input[type="text"]': { 19 | colors: { 20 | primary: 'red', 21 | secondary: 'yellow', 22 | }, 23 | }, 24 | 25 | '.container': { 26 | sizes: { 27 | medium: '3rem', 28 | }, 29 | }, 30 | 31 | '.container.card': { 32 | sizes: { 33 | medium: '4rem', 34 | }, 35 | }, 36 | 37 | '*,\n*::before,\n*::after': { 38 | hello: { 39 | world: '100%', 40 | }, 41 | }, 42 | 43 | "[type='button'],\n[type='reset']": { 44 | colors: { 45 | primary: 'blue', 46 | secondary: 'green', 47 | }, 48 | }, 49 | }, 50 | }, 51 | 52 | plugins: [tailwindcssVariables], 53 | }) 54 | ).toMatchInlineSnapshot(` 55 | " 56 | 57 | 58 | + #app { 59 | + --colors-black: rgb(0, 0, 0); 60 | + --colors-white: #ffffff 61 | + } 62 | + input[type='text'] { 63 | + --colors-primary: red; 64 | + --colors-secondary: yellow 65 | + } 66 | + .container { 67 | + --sizes-medium: 3rem 68 | + } 69 | + .container.card { 70 | + --sizes-medium: 4rem 71 | + } 72 | + *, 73 | + *::before, 74 | + *::after { 75 | + --hello-world: 100% 76 | + } 77 | + [type='button'], 78 | + [type='reset'] { 79 | + --colors-primary: blue; 80 | + --colors-secondary: green 81 | + } 82 | 83 | " 84 | `) 85 | }) 86 | -------------------------------------------------------------------------------- /__tests__/dark-mode-to-root.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /__tests__/dark-mode.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /__tests__/extend-colors.test.html: -------------------------------------------------------------------------------- 1 | tailwindcss-variables 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | tailwindcss-variables 5 | tailwindcss-variables 6 | tailwindcss-variables 7 | tailwindcss-variables 8 | tailwindcss-variables 9 | tailwindcss-variables 10 | 11 | tailwindcss-variables 12 | tailwindcss-variables 13 | tailwindcss-variables 14 | tailwindcss-variables 15 | tailwindcss-variables 16 | tailwindcss-variables 17 | tailwindcss-variables 18 | tailwindcss-variables 19 | tailwindcss-variables 20 | -------------------------------------------------------------------------------- /__tests__/fallback.test.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer components { 6 | .component .header { 7 | @apply text-red-400; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /__tests__/fallback.test.html: -------------------------------------------------------------------------------- 1 | tailwindcss-variables 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | tailwindcss-variables 5 | tailwindcss-variables 6 | tailwindcss-variables 7 | 8 | tailwindcss-variables 9 | 10 | -------------------------------------------------------------------------------- /__tests__/fallback.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | const colorVariable = require('../colorVariable') 4 | 5 | test('fallback', async () => { 6 | expect( 7 | await utils.diffOnly({ 8 | corePlugins: ['textColor', 'textOpacity', 'backgroundColor', 'backgroundOpacity'], 9 | content: [utils.content()], 10 | darkMode: false, 11 | theme: { 12 | screens: false, 13 | colors: { 14 | red: { 15 | 400: 'var(--colors-red-400 red)', 16 | 500: 'var(--colors-red red)', 17 | 600: colorVariable('var(--header-color, black)'), 18 | 700: colorVariable('var(--header-color, black)', true), 19 | 800: colorVariable('var(--header-color, black)', false), 20 | }, 21 | 22 | gray: 'var(--header-color, blue)', 23 | }, 24 | 25 | variables: { 26 | DEFAULT: { 27 | header: { 28 | color: '#ffffff', 29 | }, 30 | 31 | colors: { 32 | red: { 33 | DEFAULT: '#ff0000', 34 | 400: '#ff3f3f', 35 | }, 36 | }, 37 | }, 38 | }, 39 | }, 40 | 41 | plugins: [ 42 | tailwindcssVariables({ 43 | colorVariables: true, 44 | }), 45 | ], 46 | }) 47 | ).toMatchInlineSnapshot(` 48 | " 49 | 50 | - 51 | + :root { 52 | + --header-color: #ffffff; 53 | + --header-color-rgb: 255,255,255; 54 | + --colors-red-400: #ff3f3f; 55 | + --colors-red: #ff0000; 56 | + --colors-red-400-rgb: 255,63,63; 57 | + --colors-red-rgb: 255,0,0 58 | + } 59 | + .component .header { 60 | + color: var(--colors-red-400 red) 61 | + } 62 | + .bg-gray { 63 | + background-color: var(--header-color, blue) 64 | + } 65 | + .bg-red-400 { 66 | + background-color: var(--colors-red-400 red) 67 | + } 68 | + .bg-red-500 { 69 | + background-color: var(--colors-red red) 70 | + } 71 | + .bg-red-600 { 72 | + --tw-bg-opacity: 1; 73 | + background-color: rgba(var(--header-color-rgb, black), var(--tw-bg-opacity)) 74 | + } 75 | + .bg-red-700 { 76 | + --tw-bg-opacity: 1; 77 | + background-color: rgba(var(--header-color, black), var(--tw-bg-opacity)) 78 | + } 79 | + .bg-opacity-50 { 80 | + --tw-bg-opacity: 0.5 81 | + } 82 | + .text-red-800 { 83 | + --tw-text-opacity: 1; 84 | + color: rgba(var(--header-color-rgb, black), var(--tw-text-opacity)) 85 | + } 86 | 87 | " 88 | `) 89 | }) 90 | -------------------------------------------------------------------------------- /__tests__/force-rgb.test.html: -------------------------------------------------------------------------------- 1 | tailwindcss-variables 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | tailwindcss-variables 5 | tailwindcss-variables 6 | tailwindcss-variables 7 | tailwindcss-variables 8 | tailwindcss-variables 9 | 10 | tailwindcss-variables 11 | tailwindcss-variables 12 | tailwindcss-variables 13 | tailwindcss-variables 14 | tailwindcss-variables 15 | tailwindcss-variables 16 | tailwindcss-variables 17 | tailwindcss-variables 18 | -------------------------------------------------------------------------------- /__tests__/format-variables.test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__tests__/format-variables.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('format variables [special characters must be removed from variable names]', async () => { 5 | expect( 6 | /* eslint-disable camelcase */ 7 | await utils.diffOnly({ 8 | content: [utils.content()], 9 | darkMode: false, 10 | theme: { 11 | variables: { 12 | DEFAULT: { 13 | colors: { 14 | "hello[$&+,:;=?@#|'<>.-^*()%!]WORLD": '100%', 15 | underscore_to_dash: '100%', 16 | 'underscore_to_dash-with-dash': '100%', 17 | auto_dash: '100%', 18 | }, 19 | 20 | sizes: { 21 | 1.5: '1rem', 22 | 'foo2.0bar3.0': '2rem', 23 | baz: { 24 | 'foo3.0bar4.0': '3rem', 25 | }, 26 | }, 27 | }, 28 | 29 | "[type='button']": { 30 | "hello[$&+,:;=?@#|'<>-^*()%!]world": '100%', 31 | underscore_to_dash: '100%', 32 | 'underscore_to_dash-with-dash': '100%', 33 | auto_dash: '100%', 34 | nested_auto_dash: { 35 | color__primary: '100%', 36 | }, 37 | }, 38 | }, 39 | }, 40 | 41 | plugins: [tailwindcssVariables], 42 | }) 43 | ).toMatchInlineSnapshot(` 44 | " 45 | 46 | 47 | + :root { 48 | + --colors-hello\\.-WORLD: 100%; 49 | + --colors-underscore-to-dash: 100%; 50 | + --colors-underscore-to-dash-with-dash: 100%; 51 | + --colors-auto-dash: 100%; 52 | + --sizes-1\\.5: 1rem; 53 | + --sizes-foo2\\.0bar3\\.0: 2rem; 54 | + --sizes-baz-foo3\\.0bar4\\.0: 3rem 55 | + } 56 | + [type='button'] { 57 | + --hello-world: 100%; 58 | + --underscore-to-dash: 100%; 59 | + --underscore-to-dash-with-dash: 100%; 60 | + --auto-dash: 100%; 61 | + --nested-auto-dash-color--primary: 100% 62 | + } 63 | 64 | " 65 | `) 66 | }) 67 | -------------------------------------------------------------------------------- /__tests__/issues.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /__tests__/issues.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('issue 23', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | // body 13 | 'body-color': '#000', 14 | 'body-bg': '#fff', 15 | 'body-font-family': 'var(--font-primary)', 16 | 'body-font-size': '1rem', 17 | 'body-font-weight': 400, 18 | 'body-line-height': 1.5, 19 | 'body-font-weight2': '400', 20 | 'body-line-height2': '1.5', 21 | }, 22 | }, 23 | }, 24 | 25 | plugins: [tailwindcssVariables], 26 | }) 27 | ).toMatchInlineSnapshot(` 28 | " 29 | 30 | 31 | + :root { 32 | + --body-color: #000; 33 | + --body-bg: #fff; 34 | + --body-font-family: var(--font-primary); 35 | + --body-font-size: 1rem; 36 | + --body-font-weight: 400; 37 | + --body-line-height: 1.5; 38 | + --body-font-weight2: 400; 39 | + --body-line-height2: 1.5 40 | + } 41 | 42 | " 43 | `) 44 | }) 45 | 46 | test('issue 25', async () => { 47 | const shadow = { 48 | xs: '0 0 0 1px rgba(0, 0, 0, 0.05)', 49 | sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)', 50 | base: '0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06)', 51 | md: '0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06)', 52 | lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05)', 53 | xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04)', 54 | '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)', 55 | outline: '0 0 0 3px rgba(var(--primary), 0.6)', 56 | inner: 'inset 0 2px 4px 0 rgba(0,0,0,0.06)', 57 | none: 'none', 58 | } 59 | expect( 60 | await utils.diffOnly({ 61 | content: [utils.content()], 62 | darkMode: ['class', '[data-mode="dark"]'], 63 | theme: { 64 | variables: { 65 | DEFAULT: { 66 | shadow, 67 | }, 68 | }, 69 | 70 | darkVariables: { 71 | DEFAULT: { 72 | shadow, 73 | }, 74 | }, 75 | }, 76 | 77 | plugins: [ 78 | tailwindcssVariables({ 79 | darkToRoot: true, 80 | colorVariables: true, 81 | }), 82 | ], 83 | }) 84 | ).toMatchInlineSnapshot(` 85 | " 86 | 87 | 88 | + :root { 89 | + --shadow-xs: 0 0 0 1px rgba(0, 0, 0, 0.05); 90 | + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 91 | + --shadow-base: 0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06); 92 | + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06); 93 | + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05); 94 | + --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04); 95 | + --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); 96 | + --shadow-outline: 0 0 0 3px rgba(var(--primary), 0.6); 97 | + --shadow-inner: inset 0 2px 4px 0 rgba(0,0,0,0.06); 98 | + --shadow-none: none 99 | + } 100 | + :root[data-mode='dark'] { 101 | + --shadow-xs: 0 0 0 1px rgba(0, 0, 0, 0.05); 102 | + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 103 | + --shadow-base: 0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06); 104 | + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06); 105 | + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05); 106 | + --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04); 107 | + --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25); 108 | + --shadow-outline: 0 0 0 3px rgba(var(--primary), 0.6); 109 | + --shadow-inner: inset 0 2px 4px 0 rgba(0,0,0,0.06); 110 | + --shadow-none: none 111 | + } 112 | 113 | " 114 | `) 115 | }) 116 | 117 | test('issue 37', async () => { 118 | expect( 119 | await utils.diffOnly({ 120 | content: [utils.content()], 121 | darkMode: 'class', 122 | theme: { 123 | variables: { 124 | DEFAULT: { 125 | ONE: 'red', 126 | TWO: { 127 | DEFAULT: 'black', 128 | FOObar: 'green', 129 | THREE: { 130 | FOUR: 'white', 131 | five: 'blue', 132 | }, 133 | }, 134 | }, 135 | }, 136 | }, 137 | 138 | plugins: [tailwindcssVariables], 139 | }) 140 | ).toMatchInlineSnapshot(` 141 | " 142 | 143 | 144 | + :root { 145 | + --ONE: red; 146 | + --TWO: black; 147 | + --TWO-FOObar: green; 148 | + --TWO-THREE-FOUR: white; 149 | + --TWO-THREE-five: blue 150 | + } 151 | 152 | " 153 | `) 154 | }) 155 | 156 | test('issue 39', async () => { 157 | expect( 158 | await utils.diffOnly({ 159 | content: [utils.content()], 160 | darkMode: 'class', 161 | theme: { 162 | variables: { 163 | DEFAULT: { 164 | sizes: { 165 | 0.5: '2px', 166 | 3.5: '14px', 167 | 6.5: '18px', 168 | '1.0': { 169 | foo: '1rem', 170 | 2.4: '2rem', 171 | }, 172 | }, 173 | }, 174 | }, 175 | }, 176 | 177 | plugins: [tailwindcssVariables], 178 | }) 179 | ).toMatchInlineSnapshot(` 180 | " 181 | 182 | 183 | + :root { 184 | + --sizes-0\\.5: 2px; 185 | + --sizes-3\\.5: 14px; 186 | + --sizes-6\\.5: 18px; 187 | + --sizes-1\\.0-foo: 1rem; 188 | + --sizes-1\\.0-2\\.4: 2rem 189 | + } 190 | 191 | " 192 | `) 193 | }) 194 | -------------------------------------------------------------------------------- /__tests__/nested-variables.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /__tests__/nested-variables.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('nested variables', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | colors: { 13 | DEFAULT: '#111111', 14 | black: '#000000', 15 | buttons: { 16 | DEFAULT: '#222222', 17 | light: { 18 | DEFAULT: '#333333', 19 | white: '#ffffff', 20 | }, 21 | 22 | moon: { 23 | white: 'white', 24 | inverse: { 25 | DEFAULT: '#444444', 26 | white: 'black', 27 | }, 28 | }, 29 | }, 30 | }, 31 | }, 32 | 33 | '.container>.card, .card-body': { 34 | colors: { 35 | DEFAULT: '#555555', 36 | black: 'rgb(0, 0, 0)', 37 | buttons: { 38 | DEFAULT: '#666666', 39 | light: { 40 | DEFAULT: '#777777', 41 | white: '#ffffff', 42 | }, 43 | 44 | moon: { 45 | white: 'white', 46 | inverse: { 47 | DEFAULT: '#888888', 48 | white: 'black', 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | 57 | plugins: [tailwindcssVariables], 58 | }) 59 | ).toMatchInlineSnapshot(` 60 | " 61 | 62 | 63 | + :root { 64 | + --colors: #111111; 65 | + --colors-black: #000000; 66 | + --colors-buttons: #222222; 67 | + --colors-buttons-light: #333333; 68 | + --colors-buttons-light-white: #ffffff; 69 | + --colors-buttons-moon-white: white; 70 | + --colors-buttons-moon-inverse: #444444; 71 | + --colors-buttons-moon-inverse-white: black 72 | + } 73 | + .container>.card { 74 | + --colors: #555555; 75 | + --colors-black: rgb(0, 0, 0); 76 | + --colors-buttons: #666666; 77 | + --colors-buttons-light: #777777; 78 | + --colors-buttons-light-white: #ffffff; 79 | + --colors-buttons-moon-white: white; 80 | + --colors-buttons-moon-inverse: #888888; 81 | + --colors-buttons-moon-inverse-white: black 82 | + } 83 | + .card-body { 84 | + --colors: #555555; 85 | + --colors-black: rgb(0, 0, 0); 86 | + --colors-buttons: #666666; 87 | + --colors-buttons-light: #777777; 88 | + --colors-buttons-light-white: #ffffff; 89 | + --colors-buttons-moon-white: white; 90 | + --colors-buttons-moon-inverse: #888888; 91 | + --colors-buttons-moon-inverse-white: black 92 | + } 93 | 94 | " 95 | `) 96 | }) 97 | -------------------------------------------------------------------------------- /__tests__/plugin-api.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /__tests__/readme.test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /__tests__/test.stub: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('../jest/_utils')(__filename) 3 | 4 | it('test', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | variable: { 13 | key: 'value' 14 | }, 15 | }, 16 | }, 17 | }, 18 | plugins: [tailwindcssVariables], 19 | }) 20 | ).toMatchInlineSnapshot( 21 | ` 22 | " 23 | 24 | 25 | + :root { 26 | + --variable-key: '1' 27 | + } 28 | ` 29 | ) 30 | }) 31 | -------------------------------------------------------------------------------- /__tests__/to-base.test.html: -------------------------------------------------------------------------------- 1 | 2 | tailwindcss-variables 3 | tailwindcss-variables 4 | 5 | -------------------------------------------------------------------------------- /__tests__/to-base.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('toBase - default', async () => { 5 | expect( 6 | await utils.diffOnly( 7 | { 8 | content: [utils.content()], 9 | darkMode: 'class', 10 | corePlugins: ['textColor'], 11 | theme: { 12 | colors: { 13 | red: { 14 | 400: 'var(--colors-red-400)', 15 | 500: 'var(--colors-red-500)', 16 | }, 17 | }, 18 | 19 | variables: { 20 | DEFAULT: { 21 | colors: { 22 | red: { 23 | 400: '#000000', 24 | 500: '#111111', 25 | }, 26 | }, 27 | }, 28 | }, 29 | 30 | darkVariables: { 31 | DEFAULT: { 32 | colors: { 33 | red: { 34 | 400: '#222222', 35 | 500: '#333333', 36 | }, 37 | }, 38 | }, 39 | }, 40 | }, 41 | 42 | plugins: [tailwindcssVariables], 43 | }, 44 | 45 | true 46 | ) 47 | ).toMatchInlineSnapshot(` 48 | " 49 | 50 | 51 | + :root { 52 | + --colors-red-400: #000000; 53 | + --colors-red-500: #111111 54 | + } 55 | + :root.dark { 56 | + --colors-red-400: #222222; 57 | + --colors-red-500: #333333 58 | + } 59 | + .text-red-400 { 60 | + color: var(--colors-red-400) 61 | + } 62 | + .text-red-500 { 63 | + color: var(--colors-red-500) 64 | + } 65 | 66 | " 67 | `) 68 | }) 69 | 70 | test('toBase', async () => { 71 | expect( 72 | await utils.diffOnly( 73 | { 74 | content: [utils.content()], 75 | darkMode: 'class', 76 | corePlugins: ['textColor'], 77 | theme: { 78 | colors: { 79 | red: { 80 | 400: 'var(--colors-red-400)', 81 | 500: 'var(--colors-red-500)', 82 | }, 83 | }, 84 | 85 | variables: { 86 | DEFAULT: { 87 | colors: { 88 | red: { 89 | 400: '#000000', 90 | 500: '#111111', 91 | }, 92 | }, 93 | }, 94 | }, 95 | 96 | darkVariables: { 97 | DEFAULT: { 98 | colors: { 99 | red: { 100 | 400: '#222222', 101 | 500: '#333333', 102 | }, 103 | }, 104 | }, 105 | }, 106 | }, 107 | 108 | plugins: [ 109 | tailwindcssVariables({ 110 | toBase: true, 111 | }), 112 | ], 113 | }, 114 | 115 | true 116 | ) 117 | ).toMatchInlineSnapshot(` 118 | " 119 | 120 | 121 | + :root { 122 | + --colors-red-400: #000000; 123 | + --colors-red-500: #111111 124 | + } 125 | + :root.dark { 126 | + --colors-red-400: #222222; 127 | + --colors-red-500: #333333 128 | + } 129 | + .text-red-400 { 130 | + color: var(--colors-red-400) 131 | + } 132 | + .text-red-500 { 133 | + color: var(--colors-red-500) 134 | + } 135 | 136 | " 137 | `) 138 | }) 139 | 140 | test('if "base" styles are not added then variables should not be added', async () => { 141 | expect( 142 | await utils.diffOnly( 143 | { 144 | content: [utils.content()], 145 | darkMode: 'class', 146 | corePlugins: ['textColor'], 147 | theme: { 148 | colors: { 149 | red: { 150 | 400: 'var(--colors-red-400)', 151 | 500: 'var(--colors-red-500)', 152 | }, 153 | }, 154 | 155 | variables: { 156 | DEFAULT: { 157 | colors: { 158 | red: { 159 | 400: '#000000', 160 | 500: '#111111', 161 | }, 162 | }, 163 | }, 164 | }, 165 | 166 | darkVariables: { 167 | DEFAULT: { 168 | colors: { 169 | red: { 170 | 400: '#222222', 171 | 500: '#333333', 172 | }, 173 | }, 174 | }, 175 | }, 176 | }, 177 | 178 | plugins: [ 179 | tailwindcssVariables({ 180 | toBase: true, 181 | }), 182 | ], 183 | }, 184 | 185 | false 186 | ) 187 | ).toMatchInlineSnapshot(` 188 | " 189 | 190 | 191 | + .text-red-400 { 192 | + color: var(--colors-red-400) 193 | + } 194 | + .text-red-500 { 195 | + color: var(--colors-red-500) 196 | + } 197 | 198 | " 199 | `) 200 | }) 201 | 202 | test('if "base" styles are not added then variables should be added.', async () => { 203 | expect( 204 | await utils.diffOnly( 205 | { 206 | content: [utils.content()], 207 | darkMode: 'class', 208 | corePlugins: ['textColor'], 209 | theme: { 210 | colors: { 211 | red: { 212 | 400: 'var(--colors-red-400)', 213 | 500: 'var(--colors-red-500)', 214 | }, 215 | }, 216 | 217 | variables: { 218 | DEFAULT: { 219 | colors: { 220 | red: { 221 | 400: '#000000', 222 | 500: '#111111', 223 | }, 224 | }, 225 | }, 226 | }, 227 | 228 | darkVariables: { 229 | DEFAULT: { 230 | colors: { 231 | red: { 232 | 400: '#222222', 233 | 500: '#333333', 234 | }, 235 | }, 236 | }, 237 | }, 238 | }, 239 | 240 | plugins: [ 241 | tailwindcssVariables({ 242 | toBase: false, 243 | }), 244 | ], 245 | }, 246 | 247 | false 248 | ) 249 | ).toMatchInlineSnapshot(` 250 | " 251 | 252 | 253 | + :root { 254 | + --colors-red-400: #000000; 255 | + --colors-red-500: #111111 256 | + } 257 | + :root.dark { 258 | + --colors-red-400: #222222; 259 | + --colors-red-500: #333333 260 | + } 261 | + .text-red-400 { 262 | + color: var(--colors-red-400) 263 | + } 264 | + .text-red-500 { 265 | + color: var(--colors-red-500) 266 | + } 267 | 268 | " 269 | `) 270 | }) 271 | 272 | test('toComponents', async () => { 273 | expect( 274 | await utils.diffOnly( 275 | { 276 | content: [utils.content()], 277 | corePlugins: ['textColor'], 278 | darkMode: 'class', 279 | theme: { 280 | colors: { 281 | red: { 282 | 400: 'var(--colors-red-400)', 283 | 500: 'var(--colors-red-500)', 284 | }, 285 | }, 286 | 287 | variables: { 288 | DEFAULT: { 289 | colors: { 290 | red: { 291 | 400: '#000000', 292 | 500: '#111111', 293 | }, 294 | }, 295 | }, 296 | }, 297 | 298 | darkVariables: { 299 | DEFAULT: { 300 | colors: { 301 | red: { 302 | 400: '#222222', 303 | 500: '#333333', 304 | }, 305 | }, 306 | }, 307 | }, 308 | }, 309 | 310 | plugins: [ 311 | tailwindcssVariables({ 312 | toBase: false, 313 | }), 314 | ], 315 | }, 316 | 317 | false 318 | ) 319 | ).toMatchInlineSnapshot(` 320 | " 321 | 322 | 323 | + :root { 324 | + --colors-red-400: #000000; 325 | + --colors-red-500: #111111 326 | + } 327 | + :root.dark { 328 | + --colors-red-400: #222222; 329 | + --colors-red-500: #333333 330 | + } 331 | + .text-red-400 { 332 | + color: var(--colors-red-400) 333 | + } 334 | + .text-red-500 { 335 | + color: var(--colors-red-500) 336 | + } 337 | 338 | " 339 | `) 340 | }) 341 | -------------------------------------------------------------------------------- /__tests__/use-host.test.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/use-host.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('basic usage with host', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | colors: { 13 | black: 'rgb(0, 0, 0)', 14 | white: '#ffffff', 15 | }, 16 | 17 | sizes: { 18 | small: '10px', 19 | medium: '2rem', 20 | large: '100%', 21 | }, 22 | }, 23 | 24 | '.container': { 25 | colors: { 26 | primary: 'red', 27 | secondary: 'var(--colors-primary)', 28 | }, 29 | }, 30 | }, 31 | }, 32 | 33 | plugins: [tailwindcssVariables({ 34 | useHost: true, 35 | })], 36 | }) 37 | ).toMatchInlineSnapshot(` 38 | " 39 | 40 | 41 | + :host { 42 | + --colors-black: rgb(0, 0, 0); 43 | + --colors-white: #ffffff; 44 | + --sizes-small: 10px; 45 | + --sizes-medium: 2rem; 46 | + --sizes-large: 100% 47 | + } 48 | + .container { 49 | + --colors-primary: red; 50 | + --colors-secondary: var(--colors-primary) 51 | + } 52 | 53 | " 54 | `) 55 | }) 56 | 57 | test('basic usage with host should not work with dark', async () => { 58 | expect( 59 | await utils.diffOnly({ 60 | content: [utils.content('dark-mode-to-root')], 61 | darkMode: 'class', 62 | theme: { 63 | darkVariables: { 64 | DEFAULT: { 65 | colors: { 66 | black: 'rgb(0, 0, 0)', 67 | white: '#ffffff', 68 | }, 69 | 70 | sizes: { 71 | small: '10px', 72 | medium: '2rem', 73 | large: '100%', 74 | }, 75 | }, 76 | 77 | '.container': { 78 | colors: { 79 | primary: 'red', 80 | secondary: 'var(--colors-primary)', 81 | }, 82 | }, 83 | }, 84 | }, 85 | 86 | plugins: [tailwindcssVariables({ 87 | darkToRoot: true, 88 | useHost: true 89 | })], 90 | }) 91 | ).toMatchInlineSnapshot(` 92 | " 93 | 94 | 95 | + :host.dark { 96 | + --colors-black: rgb(0, 0, 0); 97 | + --colors-white: #ffffff; 98 | + --sizes-small: 10px; 99 | + --sizes-medium: 2rem; 100 | + --sizes-large: 100% 101 | + } 102 | + :host.dark .container { 103 | + --colors-primary: red; 104 | + --colors-secondary: var(--colors-primary) 105 | + } 106 | 107 | " 108 | `) 109 | }) 110 | -------------------------------------------------------------------------------- /__tests__/util/_utils.js: -------------------------------------------------------------------------------- 1 | const tailwind = require('tailwindcss') 2 | const snapshotDiff = require('snapshot-diff') 3 | const postcss = require('postcss') 4 | const path = require('path') 5 | const fs = require('fs') 6 | const atImport = require('postcss-import') 7 | 8 | module.exports = (contentFile) => { 9 | let utils = {} 10 | 11 | utils.run = function(config = {}, toBase = true) { 12 | let { currentTestName } = expect.getState() 13 | let filename = currentTestName + '.test.css' 14 | if (fs.existsSync(path.resolve(__dirname, '../' + filename))) { 15 | return this.runFromFile(filename, config) 16 | } 17 | 18 | return this.runInline(config, toBase) 19 | } 20 | 21 | utils.runInline = (config, toBase) => { 22 | let styles 23 | if (toBase) { 24 | styles = ['@tailwind base;', '@tailwind components;', '@tailwind utilities;'] 25 | } else { 26 | styles = ['@tailwind components;', '@tailwind utilities;'] 27 | } 28 | return postcss([tailwind({ corePlugins: [], ...config })]) 29 | .process(styles.join('\n'), { 30 | from: undefined, 31 | }) 32 | .then((result) => result.css) 33 | } 34 | 35 | utils.runFromFile = (filename, config) => { 36 | 37 | const css = fs.readFileSync(path.resolve(__dirname, '../' + filename), 'utf8') 38 | return postcss([tailwind({ corePlugins: [], ...config })]) 39 | .use(atImport()) 40 | .process(css, { 41 | from: path.resolve(__dirname, '../' + filename), 42 | }) 43 | .then((result) => result.css) 44 | } 45 | 46 | utils.diffOnly = async function(options = {}, toBase = true) { 47 | const [before, after] = await Promise.all([utils.run({}, toBase), utils.run(options, toBase)]) 48 | 49 | return `\n\n${snapshotDiff(before, after, { 50 | aAnnotation: '__REMOVE_ME__', 51 | bAnnotation: '__REMOVE_ME__', 52 | contextLines: 0, 53 | }) 54 | .replace(/\n\n@@([^@@]*)@@/g, '') // Top level @@ signs 55 | .replace(/@@([^@@]*)@@/g, '\n---\n') // In between @@ signs 56 | .replace(/[-+] __REMOVE_ME__\n/g, '') 57 | .replace(/\+ /g, '+ ') 58 | // .replace(/\+ \}\n([\s]*)\+/g, '\+ \}\n$1\+') 59 | .replace(/\+(\s+?)\}\n(\s+?)\+/g, '\\+$1\\}') 60 | .replace(/Snapshot Diff:\n/g, '') 61 | .replace(/"/g, '\'') 62 | .split('\n') 63 | .map((line) => ` ${line}`) 64 | .join('\n')}\n\n` 65 | } 66 | 67 | utils.content = (filename, ext) => { 68 | if (!ext) { 69 | ext = 'html' 70 | } 71 | 72 | if (filename) { 73 | return path.resolve(__dirname, '../' + path.parse(filename).name + '.test.' + ext) 74 | } else { 75 | return path.resolve(__dirname, '../' + path.parse(contentFile).name + '.' + ext) 76 | } 77 | } 78 | 79 | return utils 80 | } 81 | -------------------------------------------------------------------------------- /__tests__/variable-prefix.test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__tests__/variable-prefix.test.js: -------------------------------------------------------------------------------- 1 | const tailwindcssVariables = require('../src/index') 2 | const utils = require('./util/_utils')(__filename) 3 | 4 | test('variable prefix', async () => { 5 | expect( 6 | await utils.diffOnly({ 7 | content: [utils.content()], 8 | darkMode: false, 9 | theme: { 10 | variables: { 11 | DEFAULT: { 12 | colors: { 13 | primary: '#ffffff', 14 | }, 15 | }, 16 | 17 | '.container': { 18 | colors: { 19 | secondary: '#000000', 20 | }, 21 | }, 22 | }, 23 | }, 24 | 25 | plugins: [ 26 | tailwindcssVariables({ 27 | variablePrefix: '--prefix', 28 | }), 29 | ], 30 | }) 31 | ).toMatchInlineSnapshot(` 32 | " 33 | 34 | 35 | + :root { 36 | + --prefix-colors-primary: #ffffff 37 | + } 38 | + .container { 39 | + --prefix-colors-secondary: #000000 40 | + } 41 | 42 | " 43 | `) 44 | }) 45 | 46 | test('formatted variable prefix', async () => { 47 | expect( 48 | await utils.diffOnly({ 49 | content: [utils.content()], 50 | darkMode: false, 51 | theme: { 52 | variables: { 53 | DEFAULT: { 54 | colors: { 55 | primary: '#ffffff', 56 | }, 57 | }, 58 | 59 | '.container': { 60 | colors: { 61 | secondary: '#000000', 62 | }, 63 | }, 64 | }, 65 | }, 66 | 67 | plugins: [ 68 | tailwindcssVariables({ 69 | variablePrefix: '--[hello](_world)1=tail_wind', 70 | }), 71 | ], 72 | }) 73 | ).toMatchInlineSnapshot(` 74 | " 75 | 76 | 77 | + :root { 78 | + --hello-world1tail-wind-colors-primary: #ffffff 79 | + } 80 | + .container { 81 | + --hello-world1tail-wind-colors-secondary: #000000 82 | + } 83 | 84 | " 85 | `) 86 | }) 87 | -------------------------------------------------------------------------------- /api.js: -------------------------------------------------------------------------------- 1 | const pluginApi = require('./src/pluginApi') 2 | module.exports = pluginApi 3 | -------------------------------------------------------------------------------- /colorVariable.js: -------------------------------------------------------------------------------- 1 | const helpers = require('./src/helpers') 2 | module.exports = helpers.colorVariable 3 | -------------------------------------------------------------------------------- /examples/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/.npmignore -------------------------------------------------------------------------------- /examples/api-examples/advanced/components.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | select: { 3 | DEFAULT: { 4 | backgroundColor: 'var(--colors-prefix2-primary)', 5 | }, 6 | multi: { 7 | '.default-multi': { 8 | backgroundColor: 'var(--prefix2-colors-secondary)', 9 | }, 10 | '.other-multi': { 11 | backgroundColor: 'var(--prefix2-colors-warning)', 12 | }, 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/api-examples/advanced/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const merge = require('lodash/merge') 3 | const pluginThemes = require('./themes') 4 | const pluginComponents = require('./components') 5 | const variablesApi = require('../../../api') 6 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 7 | 8 | /** 9 | * @typedef {Object} plugin 10 | * @property {function} withOptions 11 | */ 12 | module.exports = plugin.withOptions( 13 | function(options) { 14 | return function({ addComponents, theme, options, config }) { 15 | let pluginOptions = merge( 16 | { 17 | variablePrefix: '--prefix1', 18 | darkToRoot: false, // default: true ( :root.dark or .dark ) 19 | }, 20 | theme('myPlugin.variableOptions', {}), 21 | ) 22 | 23 | let allThemes = pluginThemes(theme) 24 | 25 | addComponents(variablesApi.variables(merge(allThemes.themes, theme('variables', {})), pluginOptions)) 26 | 27 | addComponents(variablesApi.darkVariables(merge(allThemes.darkThemes, theme('darkVariables', {})), pluginOptions, config('darkMode'))) 28 | 29 | let allComponents = pluginComponents(theme) 30 | 31 | // Automatically register components via API. 32 | addComponents(variablesApi.getComponents('.form', allComponents)) 33 | } 34 | }, 35 | function(options) { 36 | return { 37 | // darkMode: 'class', // or media 38 | theme: { 39 | myPlugin: (theme) => ({ 40 | variableOptions: { 41 | variablePrefix: '--prefix2', 42 | }, 43 | }), 44 | }, 45 | } 46 | }, 47 | ) 48 | -------------------------------------------------------------------------------- /examples/api-examples/advanced/themes.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | themes: { 3 | DEFAULT: { 4 | colors: { 5 | primary: 'black', 6 | secondary: 'white', 7 | warning: 'indigo', 8 | }, 9 | }, 10 | '.admin': { 11 | colors: { 12 | primary: 'blue', 13 | secondary: 'green', 14 | warning: 'gray', 15 | }, 16 | }, 17 | }, 18 | darkThemes: { 19 | DEFAULT: { 20 | colors: { 21 | primary: 'yellow', 22 | secondary: 'red', 23 | warning: 'purple', 24 | }, 25 | }, 26 | '.admin': { 27 | colors: { 28 | primary: 'green', 29 | secondary: 'orange', 30 | warning: 'teal', 31 | }, 32 | }, 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /examples/api-examples/readme-source/components.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | select: { 3 | DEFAULT: { 4 | backgroundColor: 'var(--forms-colors-primary)', 5 | }, 6 | multi: { 7 | '.default-multi': { 8 | backgroundColor: 'var(--forms-colors-secondary)', 9 | }, 10 | '.other-multi': { 11 | backgroundColor: 'var(--forms-colors-warning)', 12 | }, 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/api-examples/readme-source/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/api-examples/readme-source/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const _ = require('lodash') 3 | const variablesApi = require('../../../api') 4 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 5 | const pluginComponents = require('./components') 6 | const pluginThemes = require('./themes') 7 | 8 | module.exports = plugin.withOptions( 9 | function (options) { 10 | return function ({addComponents, theme, config}) { 11 | 12 | let variableOptions = { 13 | variablePrefix: theme('myPlugin.prefix', '--forms') 14 | }; 15 | 16 | addComponents(variablesApi.variables(_.merge(pluginThemes(theme).themes, {DEFAULT: theme('myPlugin.options', {})}), variableOptions)) 17 | 18 | let darkVariables = theme('myPlugin.darkOptions', {}); 19 | if (!_.isEmpty(darkVariables)) { 20 | addComponents(variablesApi.darkVariables(darkVariables, variableOptions, config('darkMode'))) 21 | } 22 | 23 | // Automatically register components via API. 24 | addComponents(variablesApi.getComponents('.form', pluginComponents(theme))) 25 | 26 | } 27 | } 28 | ) 29 | -------------------------------------------------------------------------------- /examples/api-examples/readme-source/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: { 3 | myPlugin: { 4 | options: { 5 | colors: { 6 | primary: 'indigo', 7 | } 8 | } 9 | }, 10 | }, 11 | // plugins: [require('my-plugin')], 12 | plugins: [require('./index')], 13 | } 14 | -------------------------------------------------------------------------------- /examples/api-examples/readme-source/themes.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | themes: { 3 | DEFAULT: { 4 | colors: { 5 | primary: 'black', 6 | secondary: 'white', 7 | warning: 'orange', 8 | }, 9 | } 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /examples/api-examples/simple/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const merge = require('lodash/merge') 3 | const variablesApi = require('../../../api') 4 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 5 | 6 | /** 7 | * @typedef {Object} plugin 8 | * @property {function} withOptions 9 | */ 10 | module.exports = plugin.withOptions( 11 | function(options) { 12 | return function({ addComponents, theme, options, config }) { 13 | 14 | const myVariables = { 15 | DEFAULT: { 16 | colors: { 17 | primary: 'black', 18 | secondary: 'white', 19 | warning: 'pink', 20 | }, 21 | }, 22 | '.admin': { 23 | colors: { 24 | primary: 'blue', 25 | secondary: 'green', 26 | warning: 'gray', 27 | }, 28 | }, 29 | } 30 | let pluginOptions = merge( 31 | { 32 | variablePrefix: '--prefix1', 33 | darkToRoot: false, // default: true ( :root.dark or .dark ) 34 | }, 35 | theme('myPlugin.variableOptions', {}), 36 | ) 37 | 38 | addComponents(variablesApi.variables(merge(myVariables, theme('variables', {})), pluginOptions)) 39 | 40 | myVariables.DEFAULT.colors.primary = 'yellow' 41 | addComponents(variablesApi.darkVariables(merge(myVariables, theme('darkVariables', {})), pluginOptions, config('darkMode'))) 42 | 43 | } 44 | }, 45 | function(options) { 46 | return { 47 | // darkMode: 'class', // or media 48 | theme: { 49 | myPlugin: (theme) => ({ 50 | variableOptions: { 51 | variablePrefix: '--prefix2', 52 | }, 53 | }), 54 | }, 55 | } 56 | }, 57 | ) 58 | -------------------------------------------------------------------------------- /examples/api-examples/with-components-null-selector/components.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | '.select': { 3 | DEFAULT: { 4 | backgroundColor: 'var(--colors-prefix2-primary)', 5 | }, 6 | multi: { 7 | '.default-multi': { 8 | backgroundColor: 'var(--prefix2-colors-secondary)', 9 | }, 10 | '.other-multi': { 11 | backgroundColor: 'var(--prefix2-colors-warning)', 12 | }, 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/api-examples/with-components-null-selector/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const merge = require('lodash/merge') 3 | const pluginComponents = require('./components') 4 | const variablesApi = require('../../../api') 5 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 6 | 7 | /** 8 | * @typedef {Object} plugin 9 | * @property {function} withOptions 10 | */ 11 | module.exports = plugin.withOptions( 12 | function(options) { 13 | return function({ addComponents, theme, options, config }) { 14 | const myVariables = { 15 | DEFAULT: { 16 | colors: { 17 | primary: 'black', 18 | secondary: 'white', 19 | warning: 'pink', 20 | }, 21 | }, 22 | '.admin': { 23 | colors: { 24 | primary: 'blue', 25 | secondary: 'green', 26 | warning: 'gray', 27 | }, 28 | }, 29 | } 30 | let pluginOptions = merge( 31 | { 32 | variablePrefix: '--prefix1', 33 | darkToRoot: false, // default: true ( :root.dark or .dark ) 34 | }, 35 | theme('myPlugin.variableOptions', {}), 36 | ) 37 | 38 | addComponents(variablesApi.variables(myVariables, pluginOptions)) 39 | 40 | myVariables.DEFAULT.colors.primary = 'yellow' 41 | addComponents(variablesApi.darkVariables(myVariables, pluginOptions, config('darkMode'))) 42 | 43 | // Automatically register components via API. 44 | addComponents(variablesApi.getComponents(null, theme('myPlugin.components', {}))) 45 | } 46 | }, 47 | function(options) { 48 | return { 49 | // darkMode: 'class', // or media 50 | theme: { 51 | myPlugin: (theme) => ({ 52 | variableOptions: { 53 | variablePrefix: '--prefix2', 54 | }, 55 | components: pluginComponents(theme), 56 | }), 57 | }, 58 | } 59 | }, 60 | ) 61 | -------------------------------------------------------------------------------- /examples/api-examples/with-components/components.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | select: { 3 | DEFAULT: { 4 | backgroundColor: 'var(--colors-prefix2-primary)', 5 | }, 6 | multi: { 7 | '.default-multi': { 8 | backgroundColor: 'var(--prefix2-colors-secondary)', 9 | }, 10 | '.other-multi': { 11 | backgroundColor: 'var(--prefix2-colors-warning)', 12 | }, 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/api-examples/with-components/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const merge = require('lodash/merge') 3 | const pluginComponents = require('./components') 4 | const variablesApi = require('../../../api') 5 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 6 | 7 | /** 8 | * @typedef {Object} plugin 9 | * @property {function} withOptions 10 | */ 11 | module.exports = plugin.withOptions( 12 | function(options) { 13 | return function({ addComponents, theme, options, config }) { 14 | const myVariables = { 15 | DEFAULT: { 16 | colors: { 17 | primary: 'black', 18 | secondary: 'white', 19 | warning: 'pink', 20 | }, 21 | }, 22 | '.admin': { 23 | colors: { 24 | primary: 'blue', 25 | secondary: 'green', 26 | warning: 'gray', 27 | }, 28 | }, 29 | } 30 | let pluginOptions = merge( 31 | { 32 | variablePrefix: '--prefix1', 33 | darkToRoot: false, // default: true ( :root.dark or .dark ) 34 | }, 35 | theme('myPlugin.variableOptions', {}), 36 | ) 37 | 38 | addComponents(variablesApi.variables(myVariables, pluginOptions)) 39 | 40 | myVariables.DEFAULT.colors.primary = 'yellow' 41 | addComponents(variablesApi.darkVariables(myVariables, pluginOptions, config('darkMode'))) 42 | 43 | // Automatically register components via API. 44 | addComponents(variablesApi.getComponents('.form', theme('myPlugin.components', {}))) 45 | } 46 | }, 47 | function(options) { 48 | return { 49 | // darkMode: 'class', // or media 50 | theme: { 51 | myPlugin: (theme) => ({ 52 | variableOptions: { 53 | variablePrefix: '--prefix2', 54 | }, 55 | components: pluginComponents(theme), 56 | }), 57 | }, 58 | } 59 | }, 60 | ) 61 | -------------------------------------------------------------------------------- /examples/api-examples/with-themes/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const merge = require('lodash/merge') 3 | const pluginThemes = require('./themes') 4 | const variablesApi = require('../../../api') 5 | // const variablesApi = require('@mertasan/tailwindcss-variables/api') 6 | 7 | /** 8 | * @typedef {Object} plugin 9 | * @property {function} withOptions 10 | */ 11 | module.exports = plugin.withOptions( 12 | function(options) { 13 | return function({ addComponents, theme, options, config }) { 14 | let pluginOptions = merge( 15 | { 16 | variablePrefix: '--prefix1', 17 | darkToRoot: false, // default: true ( :root.dark or .dark ) 18 | }, 19 | theme('myPlugin.variableOptions', {}), 20 | ) 21 | 22 | let allThemes = pluginThemes(theme) 23 | 24 | addComponents(variablesApi.variables(merge(allThemes.themes, theme('variables', {})), pluginOptions)) 25 | 26 | addComponents(variablesApi.darkVariables(merge(allThemes.darkThemes, theme('darkVariables', {})), pluginOptions, config('darkMode'))) 27 | } 28 | }, 29 | function(options) { 30 | return { 31 | // darkMode: 'class', // or media 32 | theme: { 33 | myPlugin: (theme) => ({ 34 | variableOptions: { 35 | variablePrefix: '--prefix2', 36 | }, 37 | }), 38 | }, 39 | } 40 | }, 41 | ) 42 | -------------------------------------------------------------------------------- /examples/api-examples/with-themes/themes.js: -------------------------------------------------------------------------------- 1 | module.exports = (theme) => ({ 2 | themes: { 3 | DEFAULT: { 4 | colors: { 5 | primary: 'black', 6 | secondary: 'white', 7 | warning: 'indigo', 8 | }, 9 | }, 10 | '.admin': { 11 | colors: { 12 | primary: 'blue', 13 | secondary: 'green', 14 | warning: 'gray', 15 | }, 16 | }, 17 | }, 18 | darkThemes: { 19 | DEFAULT: { 20 | colors: { 21 | primary: 'yellow', 22 | secondary: 'red', 23 | warning: 'purple', 24 | }, 25 | }, 26 | '.admin': { 27 | colors: { 28 | primary: 'green', 29 | secondary: 'orange', 30 | warning: 'teal', 31 | }, 32 | }, 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /examples/color-variable-helper/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --colors-primary: #ff0; 3 | --colors-secondary: #000000; 4 | --colors-gray: #6B7280; 5 | --colors-blue: rgb(0,0,254); 6 | --colors-red-400: rgba(254,0,0,0.5); 7 | --colors-red-500: rgba(254,0,0,1); 8 | --colors-red-400-rgb: 254,0,0; 9 | --colors-red-500-rgb: 254,0,0; 10 | --colors-green: rgb(0,255,0); 11 | --colors-primary-rgb: 255,255,0; 12 | --colors-secondary-rgb: 0,0,0; 13 | --colors-gray-rgb: 107,114,128; 14 | --colors-blue-rgb: 0,0,254; 15 | --colors-green-rgb: 0,255,0; 16 | --sizes-small: 10px; 17 | --sizes-medium: 2rem; 18 | --sizes-large: 100% 19 | } 20 | .bg-secondary { 21 | --tw-bg-opacity: 1; 22 | background-color: rgba(var(--colors-secondary-rgb), var(--tw-bg-opacity)) 23 | } 24 | .bg-gray { 25 | background-color: var(--colors-gray) 26 | } 27 | .bg-red-400 { 28 | --tw-bg-opacity: 1; 29 | background-color: rgba(var(--colors-red-400-rgb), var(--tw-bg-opacity)) 30 | } 31 | .bg-red-500 { 32 | --tw-bg-opacity: 1; 33 | background-color: rgba(var(--colors-red-500-rgb), var(--tw-bg-opacity)) 34 | } 35 | .bg-red-600 { 36 | background-color: var(--colors-red-500) 37 | } 38 | .bg-green { 39 | background-color: var(--colors-green) 40 | } 41 | .bg-white { 42 | --tw-bg-opacity: 1; 43 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)) 44 | } 45 | .bg-opacity-50 { 46 | --tw-bg-opacity: 0.5 47 | } 48 | .text-primary { 49 | --tw-text-opacity: 1; 50 | color: rgba(var(--colors-primary-rgb), var(--tw-text-opacity)) 51 | } 52 | .text-blue { 53 | --tw-text-opacity: 1; 54 | color: rgba(var(--colors-blue-rgb), var(--tw-text-opacity)) 55 | } 56 | .text-opacity-50 { 57 | --tw-text-opacity: 0.5 58 | } -------------------------------------------------------------------------------- /examples/color-variable-helper/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/color-variable-helper/image.png -------------------------------------------------------------------------------- /examples/color-variable-helper/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | colorVariable() example using @mertasan/tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [colorVariable() example] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/color-variable-helper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "color-variable-helper", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/color-variable-helper/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --colors-primary: #ff0; 373 | --colors-secondary: #000000; 374 | --colors-gray: #6B7280; 375 | --colors-blue: rgb(0,0,254); 376 | --colors-red-400: rgba(254,0,0,0.5); 377 | --colors-red-500: rgba(254,0,0,1); 378 | --colors-red-400-rgb: 254,0,0; 379 | --colors-red-500-rgb: 254,0,0; 380 | --colors-green: rgb(0,255,0); 381 | --colors-primary-rgb: 255,255,0; 382 | --colors-secondary-rgb: 0,0,0; 383 | --colors-gray-rgb: 107,114,128; 384 | --colors-blue-rgb: 0,0,254; 385 | --colors-green-rgb: 0,255,0; 386 | --sizes-small: 10px; 387 | --sizes-medium: 2rem; 388 | --sizes-large: 100%; 389 | } 390 | .container { 391 | width: 100%; 392 | } 393 | .order-1 { 394 | order: 1; 395 | } 396 | .mx-auto { 397 | margin-left: auto; 398 | margin-right: auto; 399 | } 400 | .-mx-3 { 401 | margin-left: -0.75rem; 402 | margin-right: -0.75rem; 403 | } 404 | .mb-4 { 405 | margin-bottom: 1rem; 406 | } 407 | .mt-4 { 408 | margin-top: 1rem; 409 | } 410 | .mb-12 { 411 | margin-bottom: 3rem; 412 | } 413 | .flex { 414 | display: flex; 415 | } 416 | .hidden { 417 | display: none; 418 | } 419 | .w-full { 420 | width: 100%; 421 | } 422 | .max-w-6xl { 423 | max-width: 72rem; 424 | } 425 | .flex-wrap { 426 | flex-wrap: wrap; 427 | } 428 | .items-center { 429 | align-items: center; 430 | } 431 | .bg-secondary { 432 | --tw-bg-opacity: 1; 433 | background-color: rgba(var(--colors-secondary-rgb), var(--tw-bg-opacity)); 434 | } 435 | .bg-gray { 436 | background-color: var(--colors-gray); 437 | } 438 | .bg-red-400 { 439 | --tw-bg-opacity: 1; 440 | background-color: rgba(var(--colors-red-400-rgb), var(--tw-bg-opacity)); 441 | } 442 | .bg-red-500 { 443 | --tw-bg-opacity: 1; 444 | background-color: rgba(var(--colors-red-500-rgb), var(--tw-bg-opacity)); 445 | } 446 | .bg-red-600 { 447 | background-color: var(--colors-red-500); 448 | } 449 | .bg-green { 450 | background-color: var(--colors-green); 451 | } 452 | .bg-white { 453 | --tw-bg-opacity: 1; 454 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 455 | } 456 | .bg-opacity-50 { 457 | --tw-bg-opacity: 0.5; 458 | } 459 | .py-20 { 460 | padding-top: 5rem; 461 | padding-bottom: 5rem; 462 | } 463 | .px-4 { 464 | padding-left: 1rem; 465 | padding-right: 1rem; 466 | } 467 | .px-10 { 468 | padding-left: 2.5rem; 469 | padding-right: 2.5rem; 470 | } 471 | .px-3 { 472 | padding-left: 0.75rem; 473 | padding-right: 0.75rem; 474 | } 475 | .text-3xl { 476 | font-size: 1.875rem; 477 | line-height: 2.25rem; 478 | } 479 | .text-2xl { 480 | font-size: 1.5rem; 481 | line-height: 2rem; 482 | } 483 | .text-base { 484 | font-size: 1rem; 485 | line-height: 1.5rem; 486 | } 487 | .font-bold { 488 | font-weight: 700; 489 | } 490 | .font-semibold { 491 | font-weight: 600; 492 | } 493 | .font-medium { 494 | font-weight: 500; 495 | } 496 | .leading-tight { 497 | line-height: 1.25; 498 | } 499 | .tracking-tight { 500 | letter-spacing: -0.025em; 501 | } 502 | .text-primary { 503 | --tw-text-opacity: 1; 504 | color: rgba(var(--colors-primary-rgb), var(--tw-text-opacity)); 505 | } 506 | .text-blue { 507 | --tw-text-opacity: 1; 508 | color: rgba(var(--colors-blue-rgb), var(--tw-text-opacity)); 509 | } 510 | .text-opacity-50 { 511 | --tw-text-opacity: 0.5; 512 | } -------------------------------------------------------------------------------- /examples/color-variable-helper/tailwind.config.js: -------------------------------------------------------------------------------- 1 | // const colorVariable = require('@mertasan/tailwindcss-variables/colorVariable') 2 | const colorVariable = require('../../colorVariable') 3 | 4 | /** 5 | * Usage: 6 | * colorVariable('--colors-primary') 7 | * or 8 | * colorVariable('var(--colors-primary)') 9 | */ 10 | module.exports = { 11 | corePlugins: process.env.CLEAN ? ['textColor', 'textOpacity', 'backgroundColor', 'backgroundOpacity'] : {}, 12 | content: ['./index.html'], 13 | darkMode: 'class', 14 | theme: {screens: false, 15 | colors: { 16 | primary: colorVariable('--colors-primary'), // HEX (3 digits) 17 | secondary: colorVariable('var(--colors-secondary)'), // HEX (6 digits) 18 | white: '#ffffff', // no variable 19 | blue: colorVariable('var(--colors-blue)'), // RGB 20 | red: { 21 | 400: colorVariable('var(--colors-red-400)'), // RGBA 22 | 500: colorVariable('var(--colors-red-500)'), // RGBA 23 | 600: 'var(--colors-red-500)', // RGBA (without using colorVariable() helper) 24 | }, 25 | gray: 'var(--colors-gray)', // HEX (6 digits) (without using colorVariable() helper) 26 | green: 'var(--colors-green)', // RGB (without using colorVariable() helper) 27 | }, 28 | variables: { 29 | DEFAULT: { 30 | colors: { 31 | primary: '#ff0', 32 | secondary: '#000000', 33 | gray: '#6B7280', 34 | blue: 'rgb(0,0,254)', 35 | red: { 36 | 400: 'rgba(254,0,0,0.5)', 37 | 500: 'rgba(254,0,0,1)', 38 | }, 39 | green: 'rgb(0,255,0)', 40 | }, 41 | sizes: { 42 | small: '10px', 43 | medium: '2rem', 44 | large: '100%', 45 | }, 46 | }, 47 | }, 48 | }, 49 | plugins: [ 50 | require('../../src/index')({ 51 | colorVariables: true 52 | }) 53 | ], 54 | } 55 | -------------------------------------------------------------------------------- /examples/color-variable-helper/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/dark-custom-selector/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --colors-red-50: #ff3232; 6 | --colors-red-500: #ff0000; 7 | --colors-red-900: #d70000 8 | } 9 | .container { 10 | --sizes-medium: 1.5rem; 11 | --sizes-container: 2rem 12 | } 13 | :root.custom-dark-selector { 14 | --colors-red-50: #c665ff; 15 | --colors-red-500: #9433f1; 16 | --colors-red-900: #6c0bc9 17 | } 18 | :root.custom-dark-selector .container { 19 | --colors-red-50: #ff0000 20 | } -------------------------------------------------------------------------------- /examples/dark-custom-selector/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/dark-custom-selector/image.png -------------------------------------------------------------------------------- /examples/dark-custom-selector/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dark Mode (class) example using tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [dark mode with "darkSelector" option] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/dark-custom-selector/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dark-custom-selector", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/dark-custom-selector/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --sizes-small: 1rem; 373 | --sizes-medium: 2rem; 374 | --sizes-large: 3rem; 375 | --colors-red-50: #ff3232; 376 | --colors-red-500: #ff0000; 377 | --colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --sizes-medium: 1.5rem; 382 | --sizes-container: 2rem; 383 | } 384 | 385 | :root.custom-dark-selector { 386 | --colors-red-50: #c665ff; 387 | --colors-red-500: #9433f1; 388 | --colors-red-900: #6c0bc9; 389 | } 390 | 391 | :root.custom-dark-selector .container { 392 | --colors-red-50: #ff0000; 393 | } 394 | .container { 395 | width: 100%; 396 | } 397 | @media (min-width: 640px) { 398 | 399 | .container { 400 | max-width: 640px; 401 | } 402 | } 403 | @media (min-width: 768px) { 404 | 405 | .container { 406 | max-width: 768px; 407 | } 408 | } 409 | @media (min-width: 1024px) { 410 | 411 | .container { 412 | max-width: 1024px; 413 | } 414 | } 415 | @media (min-width: 1280px) { 416 | 417 | .container { 418 | max-width: 1280px; 419 | } 420 | } 421 | @media (min-width: 1536px) { 422 | 423 | .container { 424 | max-width: 1536px; 425 | } 426 | } 427 | .order-1 { 428 | order: 1; 429 | } 430 | .mx-auto { 431 | margin-left: auto; 432 | margin-right: auto; 433 | } 434 | .-mx-3 { 435 | margin-left: -0.75rem; 436 | margin-right: -0.75rem; 437 | } 438 | .mb-4 { 439 | margin-bottom: 1rem; 440 | } 441 | .mt-4 { 442 | margin-top: 1rem; 443 | } 444 | .mb-12 { 445 | margin-bottom: 3rem; 446 | } 447 | .flex { 448 | display: flex; 449 | } 450 | .w-full { 451 | width: 100%; 452 | } 453 | .max-w-6xl { 454 | max-width: 72rem; 455 | } 456 | .flex-wrap { 457 | flex-wrap: wrap; 458 | } 459 | .items-center { 460 | align-items: center; 461 | } 462 | .bg-gray-50 { 463 | --tw-bg-opacity: 1; 464 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 465 | } 466 | .py-20 { 467 | padding-top: 5rem; 468 | padding-bottom: 5rem; 469 | } 470 | .px-4 { 471 | padding-left: 1rem; 472 | padding-right: 1rem; 473 | } 474 | .px-10 { 475 | padding-left: 2.5rem; 476 | padding-right: 2.5rem; 477 | } 478 | .px-3 { 479 | padding-left: 0.75rem; 480 | padding-right: 0.75rem; 481 | } 482 | .text-3xl { 483 | font-size: 1.875rem; 484 | line-height: 2.25rem; 485 | } 486 | .text-2xl { 487 | font-size: 1.5rem; 488 | line-height: 2rem; 489 | } 490 | .text-base { 491 | font-size: 1rem; 492 | line-height: 1.5rem; 493 | } 494 | .font-bold { 495 | font-weight: 700; 496 | } 497 | .font-semibold { 498 | font-weight: 600; 499 | } 500 | .font-medium { 501 | font-weight: 500; 502 | } 503 | .leading-tight { 504 | line-height: 1.25; 505 | } 506 | .tracking-tight { 507 | letter-spacing: -0.025em; 508 | } 509 | .text-green-500 { 510 | --tw-text-opacity: 1; 511 | color: rgb(34 197 94 / var(--tw-text-opacity)); 512 | } 513 | .text-blue-500 { 514 | --tw-text-opacity: 1; 515 | color: rgb(59 130 246 / var(--tw-text-opacity)); 516 | } 517 | .hover\:text-blue-600:hover { 518 | --tw-text-opacity: 1; 519 | color: rgb(37 99 235 / var(--tw-text-opacity)); 520 | } 521 | @media (min-width: 640px) { 522 | 523 | .sm\:max-w-sm { 524 | max-width: 24rem; 525 | } 526 | 527 | .sm\:px-20 { 528 | padding-left: 5rem; 529 | padding-right: 5rem; 530 | } 531 | 532 | .sm\:text-5xl { 533 | font-size: 3rem; 534 | line-height: 1; 535 | } 536 | 537 | .sm\:text-3xl { 538 | font-size: 1.875rem; 539 | line-height: 2.25rem; 540 | } 541 | } 542 | @media (min-width: 768px) { 543 | 544 | .md\:px-32 { 545 | padding-left: 8rem; 546 | padding-right: 8rem; 547 | } 548 | } 549 | @media (min-width: 1024px) { 550 | 551 | .lg\:order-1 { 552 | order: 1; 553 | } 554 | 555 | .lg\:mb-0 { 556 | margin-bottom: 0px; 557 | } 558 | 559 | .lg\:w-1\/2 { 560 | width: 50%; 561 | } 562 | 563 | .lg\:max-w-md { 564 | max-width: 28rem; 565 | } 566 | 567 | .lg\:max-w-full { 568 | max-width: 100%; 569 | } 570 | 571 | .lg\:px-16 { 572 | padding-left: 4rem; 573 | padding-right: 4rem; 574 | } 575 | } 576 | @media (min-width: 1280px) { 577 | 578 | .xl\:mb-6 { 579 | margin-bottom: 1.5rem; 580 | } 581 | 582 | .xl\:mt-6 { 583 | margin-top: 1.5rem; 584 | } 585 | } -------------------------------------------------------------------------------- /examples/dark-custom-selector/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: ['class', '.custom-dark-selector'], 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | }, 13 | colors: { 14 | red: { 15 | 50: '#ff3232', 16 | 500: '#ff0000', 17 | 900: '#d70000', 18 | }, 19 | }, 20 | }, 21 | '.container': { 22 | sizes: { 23 | medium: '1.5rem', 24 | container: '2rem', 25 | }, 26 | }, 27 | }), 28 | darkVariables: (theme) => ({ 29 | DEFAULT: { 30 | colors: { 31 | red: { 32 | 50: '#c665ff', 33 | 500: '#9433f1', 34 | 900: '#6c0bc9', 35 | }, 36 | }, 37 | }, 38 | '.container': { 39 | colors: { 40 | red: { 41 | 50: '#ff0000', 42 | }, 43 | }, 44 | }, 45 | }), 46 | }, 47 | plugins: [ 48 | require('../../src/index')({ 49 | darkToRoot: true, 50 | }), 51 | ], 52 | } 53 | -------------------------------------------------------------------------------- /examples/dark-custom-selector/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --colors-red-50: #ff3232; 6 | --colors-red-500: #ff0000; 7 | --colors-red-900: #d70000 8 | } 9 | .container { 10 | --sizes-medium: 1.5rem; 11 | --sizes-container: 2rem 12 | } 13 | :root.dark { 14 | --colors-red-50: #c665ff; 15 | --colors-red-500: #9433f1; 16 | --colors-red-900: #6c0bc9 17 | } 18 | :root.dark .container { 19 | --colors-red-50: #ff0000 20 | } -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/dark-with-class-to-root/image.png -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dark Mode (class) example using tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [dark mode with "class" mode and darkToRoot option] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dark-with-class-to-root", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --sizes-small: 1rem; 373 | --sizes-medium: 2rem; 374 | --sizes-large: 3rem; 375 | --colors-red-50: #ff3232; 376 | --colors-red-500: #ff0000; 377 | --colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --sizes-medium: 1.5rem; 382 | --sizes-container: 2rem; 383 | } 384 | 385 | :root.dark { 386 | --colors-red-50: #c665ff; 387 | --colors-red-500: #9433f1; 388 | --colors-red-900: #6c0bc9; 389 | } 390 | 391 | :root.dark .container { 392 | --colors-red-50: #ff0000; 393 | } 394 | .container { 395 | width: 100%; 396 | } 397 | @media (min-width: 640px) { 398 | 399 | .container { 400 | max-width: 640px; 401 | } 402 | } 403 | @media (min-width: 768px) { 404 | 405 | .container { 406 | max-width: 768px; 407 | } 408 | } 409 | @media (min-width: 1024px) { 410 | 411 | .container { 412 | max-width: 1024px; 413 | } 414 | } 415 | @media (min-width: 1280px) { 416 | 417 | .container { 418 | max-width: 1280px; 419 | } 420 | } 421 | @media (min-width: 1536px) { 422 | 423 | .container { 424 | max-width: 1536px; 425 | } 426 | } 427 | .order-1 { 428 | order: 1; 429 | } 430 | .mx-auto { 431 | margin-left: auto; 432 | margin-right: auto; 433 | } 434 | .-mx-3 { 435 | margin-left: -0.75rem; 436 | margin-right: -0.75rem; 437 | } 438 | .mb-4 { 439 | margin-bottom: 1rem; 440 | } 441 | .mt-4 { 442 | margin-top: 1rem; 443 | } 444 | .mb-12 { 445 | margin-bottom: 3rem; 446 | } 447 | .flex { 448 | display: flex; 449 | } 450 | .w-full { 451 | width: 100%; 452 | } 453 | .max-w-6xl { 454 | max-width: 72rem; 455 | } 456 | .flex-wrap { 457 | flex-wrap: wrap; 458 | } 459 | .items-center { 460 | align-items: center; 461 | } 462 | .bg-gray-50 { 463 | --tw-bg-opacity: 1; 464 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 465 | } 466 | .py-20 { 467 | padding-top: 5rem; 468 | padding-bottom: 5rem; 469 | } 470 | .px-4 { 471 | padding-left: 1rem; 472 | padding-right: 1rem; 473 | } 474 | .px-10 { 475 | padding-left: 2.5rem; 476 | padding-right: 2.5rem; 477 | } 478 | .px-3 { 479 | padding-left: 0.75rem; 480 | padding-right: 0.75rem; 481 | } 482 | .text-3xl { 483 | font-size: 1.875rem; 484 | line-height: 2.25rem; 485 | } 486 | .text-2xl { 487 | font-size: 1.5rem; 488 | line-height: 2rem; 489 | } 490 | .text-base { 491 | font-size: 1rem; 492 | line-height: 1.5rem; 493 | } 494 | .font-bold { 495 | font-weight: 700; 496 | } 497 | .font-semibold { 498 | font-weight: 600; 499 | } 500 | .font-medium { 501 | font-weight: 500; 502 | } 503 | .leading-tight { 504 | line-height: 1.25; 505 | } 506 | .tracking-tight { 507 | letter-spacing: -0.025em; 508 | } 509 | .text-green-500 { 510 | --tw-text-opacity: 1; 511 | color: rgb(34 197 94 / var(--tw-text-opacity)); 512 | } 513 | .text-blue-500 { 514 | --tw-text-opacity: 1; 515 | color: rgb(59 130 246 / var(--tw-text-opacity)); 516 | } 517 | .hover\:text-blue-600:hover { 518 | --tw-text-opacity: 1; 519 | color: rgb(37 99 235 / var(--tw-text-opacity)); 520 | } 521 | @media (min-width: 640px) { 522 | 523 | .sm\:max-w-sm { 524 | max-width: 24rem; 525 | } 526 | 527 | .sm\:px-20 { 528 | padding-left: 5rem; 529 | padding-right: 5rem; 530 | } 531 | 532 | .sm\:text-5xl { 533 | font-size: 3rem; 534 | line-height: 1; 535 | } 536 | 537 | .sm\:text-3xl { 538 | font-size: 1.875rem; 539 | line-height: 2.25rem; 540 | } 541 | } 542 | @media (min-width: 768px) { 543 | 544 | .md\:px-32 { 545 | padding-left: 8rem; 546 | padding-right: 8rem; 547 | } 548 | } 549 | @media (min-width: 1024px) { 550 | 551 | .lg\:order-1 { 552 | order: 1; 553 | } 554 | 555 | .lg\:mb-0 { 556 | margin-bottom: 0px; 557 | } 558 | 559 | .lg\:w-1\/2 { 560 | width: 50%; 561 | } 562 | 563 | .lg\:max-w-md { 564 | max-width: 28rem; 565 | } 566 | 567 | .lg\:max-w-full { 568 | max-width: 100%; 569 | } 570 | 571 | .lg\:px-16 { 572 | padding-left: 4rem; 573 | padding-right: 4rem; 574 | } 575 | } 576 | @media (min-width: 1280px) { 577 | 578 | .xl\:mb-6 { 579 | margin-bottom: 1.5rem; 580 | } 581 | 582 | .xl\:mt-6 { 583 | margin-top: 1.5rem; 584 | } 585 | } -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: 'class', 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | }, 13 | colors: { 14 | red: { 15 | 50: '#ff3232', 16 | 500: '#ff0000', 17 | 900: '#d70000', 18 | }, 19 | }, 20 | }, 21 | '.container': { 22 | sizes: { 23 | medium: '1.5rem', 24 | container: '2rem', 25 | }, 26 | }, 27 | }), 28 | darkVariables: (theme) => ({ 29 | DEFAULT: { 30 | colors: { 31 | red: { 32 | 50: '#c665ff', 33 | 500: '#9433f1', 34 | 900: '#6c0bc9', 35 | }, 36 | }, 37 | }, 38 | '.container': { 39 | colors: { 40 | red: { 41 | 50: '#ff0000', 42 | }, 43 | }, 44 | }, 45 | }), 46 | }, 47 | plugins: [ 48 | require('../../src/index')({ 49 | darkToRoot: true, 50 | }), 51 | ], 52 | } 53 | -------------------------------------------------------------------------------- /examples/dark-with-class-to-root/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/dark-with-class/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --colors-red-50: #ff3232; 6 | --colors-red-500: #ff0000; 7 | --colors-red-900: #d70000 8 | } 9 | .container { 10 | --sizes-medium: 1.5rem; 11 | --sizes-container: 2rem 12 | } 13 | .dark { 14 | --colors-red-50: #c665ff; 15 | --colors-red-500: #9433f1; 16 | --colors-red-900: #6c0bc9 17 | } 18 | .dark .container { 19 | --colors-red-50: #ff0000 20 | } -------------------------------------------------------------------------------- /examples/dark-with-class/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/dark-with-class/image.png -------------------------------------------------------------------------------- /examples/dark-with-class/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dark Mode (class) example using tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Tailwindcss Variables 18 | 19 | [dark mode with "class"] 20 | 21 | source 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/dark-with-class/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dark-with-class", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/dark-with-class/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --sizes-small: 1rem; 373 | --sizes-medium: 2rem; 374 | --sizes-large: 3rem; 375 | --colors-red-50: #ff3232; 376 | --colors-red-500: #ff0000; 377 | --colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --sizes-medium: 1.5rem; 382 | --sizes-container: 2rem; 383 | } 384 | 385 | .dark { 386 | --colors-red-50: #c665ff; 387 | --colors-red-500: #9433f1; 388 | --colors-red-900: #6c0bc9; 389 | } 390 | 391 | .dark .container { 392 | --colors-red-50: #ff0000; 393 | } 394 | .container { 395 | width: 100%; 396 | } 397 | @media (min-width: 640px) { 398 | 399 | .container { 400 | max-width: 640px; 401 | } 402 | } 403 | @media (min-width: 768px) { 404 | 405 | .container { 406 | max-width: 768px; 407 | } 408 | } 409 | @media (min-width: 1024px) { 410 | 411 | .container { 412 | max-width: 1024px; 413 | } 414 | } 415 | @media (min-width: 1280px) { 416 | 417 | .container { 418 | max-width: 1280px; 419 | } 420 | } 421 | @media (min-width: 1536px) { 422 | 423 | .container { 424 | max-width: 1536px; 425 | } 426 | } 427 | .order-1 { 428 | order: 1; 429 | } 430 | .mx-auto { 431 | margin-left: auto; 432 | margin-right: auto; 433 | } 434 | .-mx-3 { 435 | margin-left: -0.75rem; 436 | margin-right: -0.75rem; 437 | } 438 | .mb-4 { 439 | margin-bottom: 1rem; 440 | } 441 | .mt-4 { 442 | margin-top: 1rem; 443 | } 444 | .mb-12 { 445 | margin-bottom: 3rem; 446 | } 447 | .flex { 448 | display: flex; 449 | } 450 | .w-full { 451 | width: 100%; 452 | } 453 | .max-w-6xl { 454 | max-width: 72rem; 455 | } 456 | .flex-wrap { 457 | flex-wrap: wrap; 458 | } 459 | .items-center { 460 | align-items: center; 461 | } 462 | .bg-gray-50 { 463 | --tw-bg-opacity: 1; 464 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 465 | } 466 | .py-20 { 467 | padding-top: 5rem; 468 | padding-bottom: 5rem; 469 | } 470 | .px-4 { 471 | padding-left: 1rem; 472 | padding-right: 1rem; 473 | } 474 | .px-10 { 475 | padding-left: 2.5rem; 476 | padding-right: 2.5rem; 477 | } 478 | .px-3 { 479 | padding-left: 0.75rem; 480 | padding-right: 0.75rem; 481 | } 482 | .text-3xl { 483 | font-size: 1.875rem; 484 | line-height: 2.25rem; 485 | } 486 | .text-2xl { 487 | font-size: 1.5rem; 488 | line-height: 2rem; 489 | } 490 | .text-base { 491 | font-size: 1rem; 492 | line-height: 1.5rem; 493 | } 494 | .font-bold { 495 | font-weight: 700; 496 | } 497 | .font-semibold { 498 | font-weight: 600; 499 | } 500 | .font-medium { 501 | font-weight: 500; 502 | } 503 | .leading-tight { 504 | line-height: 1.25; 505 | } 506 | .tracking-tight { 507 | letter-spacing: -0.025em; 508 | } 509 | .text-green-500 { 510 | --tw-text-opacity: 1; 511 | color: rgb(34 197 94 / var(--tw-text-opacity)); 512 | } 513 | .text-blue-500 { 514 | --tw-text-opacity: 1; 515 | color: rgb(59 130 246 / var(--tw-text-opacity)); 516 | } 517 | .hover\:text-blue-600:hover { 518 | --tw-text-opacity: 1; 519 | color: rgb(37 99 235 / var(--tw-text-opacity)); 520 | } 521 | @media (min-width: 640px) { 522 | 523 | .sm\:max-w-sm { 524 | max-width: 24rem; 525 | } 526 | 527 | .sm\:px-20 { 528 | padding-left: 5rem; 529 | padding-right: 5rem; 530 | } 531 | 532 | .sm\:text-5xl { 533 | font-size: 3rem; 534 | line-height: 1; 535 | } 536 | 537 | .sm\:text-3xl { 538 | font-size: 1.875rem; 539 | line-height: 2.25rem; 540 | } 541 | } 542 | @media (min-width: 768px) { 543 | 544 | .md\:px-32 { 545 | padding-left: 8rem; 546 | padding-right: 8rem; 547 | } 548 | } 549 | @media (min-width: 1024px) { 550 | 551 | .lg\:order-1 { 552 | order: 1; 553 | } 554 | 555 | .lg\:mb-0 { 556 | margin-bottom: 0px; 557 | } 558 | 559 | .lg\:w-1\/2 { 560 | width: 50%; 561 | } 562 | 563 | .lg\:max-w-md { 564 | max-width: 28rem; 565 | } 566 | 567 | .lg\:max-w-full { 568 | max-width: 100%; 569 | } 570 | 571 | .lg\:px-16 { 572 | padding-left: 4rem; 573 | padding-right: 4rem; 574 | } 575 | } 576 | @media (min-width: 1280px) { 577 | 578 | .xl\:mb-6 { 579 | margin-bottom: 1.5rem; 580 | } 581 | 582 | .xl\:mt-6 { 583 | margin-top: 1.5rem; 584 | } 585 | } -------------------------------------------------------------------------------- /examples/dark-with-class/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: 'class', 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | }, 13 | colors: { 14 | red: { 15 | 50: '#ff3232', 16 | 500: '#ff0000', 17 | 900: '#d70000', 18 | }, 19 | }, 20 | }, 21 | '.container': { 22 | sizes: { 23 | medium: '1.5rem', 24 | container: '2rem', 25 | }, 26 | }, 27 | }), 28 | darkVariables: (theme) => ({ 29 | DEFAULT: { 30 | colors: { 31 | red: { 32 | 50: '#c665ff', 33 | 500: '#9433f1', 34 | 900: '#6c0bc9', 35 | }, 36 | }, 37 | }, 38 | '.container': { 39 | colors: { 40 | red: { 41 | 50: '#ff0000', 42 | }, 43 | }, 44 | }, 45 | }), 46 | }, 47 | plugins: [ 48 | require('../../src/index')({ 49 | darkToRoot: false, 50 | }), 51 | ], 52 | } 53 | -------------------------------------------------------------------------------- /examples/dark-with-class/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/dark-with-media/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --colors-red-50: #ff3232; 6 | --colors-red-500: #ff0000; 7 | --colors-red-900: #d70000 8 | } 9 | .container { 10 | --sizes-medium: 1.5rem; 11 | --sizes-container: 2rem 12 | } 13 | @media (prefers-color-scheme: dark) { 14 | :root { 15 | --colors-red-50: #c665ff; 16 | --colors-red-500: #9433f1; 17 | --colors-red-900: #6c0bc9 18 | } 19 | .container { 20 | --colors-red-50: #ff0000 21 | } 22 | } -------------------------------------------------------------------------------- /examples/dark-with-media/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/dark-with-media/image.png -------------------------------------------------------------------------------- /examples/dark-with-media/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dark Mode (media) example using @mertasan/tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [dark mode with "media"] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/dark-with-media/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dark-with-media", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/dark-with-media/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --sizes-small: 1rem; 373 | --sizes-medium: 2rem; 374 | --sizes-large: 3rem; 375 | --colors-red-50: #ff3232; 376 | --colors-red-500: #ff0000; 377 | --colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --sizes-medium: 1.5rem; 382 | --sizes-container: 2rem; 383 | } 384 | 385 | @media (prefers-color-scheme: dark) { 386 | 387 | :root { 388 | --colors-red-50: #c665ff; 389 | --colors-red-500: #9433f1; 390 | --colors-red-900: #6c0bc9; 391 | } 392 | 393 | .container { 394 | --colors-red-50: #ff0000; 395 | } 396 | } 397 | .container { 398 | width: 100%; 399 | } 400 | @media (min-width: 640px) { 401 | 402 | .container { 403 | max-width: 640px; 404 | } 405 | } 406 | @media (min-width: 768px) { 407 | 408 | .container { 409 | max-width: 768px; 410 | } 411 | } 412 | @media (min-width: 1024px) { 413 | 414 | .container { 415 | max-width: 1024px; 416 | } 417 | } 418 | @media (min-width: 1280px) { 419 | 420 | .container { 421 | max-width: 1280px; 422 | } 423 | } 424 | @media (min-width: 1536px) { 425 | 426 | .container { 427 | max-width: 1536px; 428 | } 429 | } 430 | .order-1 { 431 | order: 1; 432 | } 433 | .mx-auto { 434 | margin-left: auto; 435 | margin-right: auto; 436 | } 437 | .-mx-3 { 438 | margin-left: -0.75rem; 439 | margin-right: -0.75rem; 440 | } 441 | .mb-4 { 442 | margin-bottom: 1rem; 443 | } 444 | .mt-4 { 445 | margin-top: 1rem; 446 | } 447 | .mb-12 { 448 | margin-bottom: 3rem; 449 | } 450 | .flex { 451 | display: flex; 452 | } 453 | .w-full { 454 | width: 100%; 455 | } 456 | .max-w-6xl { 457 | max-width: 72rem; 458 | } 459 | .flex-wrap { 460 | flex-wrap: wrap; 461 | } 462 | .items-center { 463 | align-items: center; 464 | } 465 | .bg-gray-50 { 466 | --tw-bg-opacity: 1; 467 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 468 | } 469 | .py-20 { 470 | padding-top: 5rem; 471 | padding-bottom: 5rem; 472 | } 473 | .px-4 { 474 | padding-left: 1rem; 475 | padding-right: 1rem; 476 | } 477 | .px-10 { 478 | padding-left: 2.5rem; 479 | padding-right: 2.5rem; 480 | } 481 | .px-3 { 482 | padding-left: 0.75rem; 483 | padding-right: 0.75rem; 484 | } 485 | .text-3xl { 486 | font-size: 1.875rem; 487 | line-height: 2.25rem; 488 | } 489 | .text-2xl { 490 | font-size: 1.5rem; 491 | line-height: 2rem; 492 | } 493 | .text-base { 494 | font-size: 1rem; 495 | line-height: 1.5rem; 496 | } 497 | .font-bold { 498 | font-weight: 700; 499 | } 500 | .font-semibold { 501 | font-weight: 600; 502 | } 503 | .font-medium { 504 | font-weight: 500; 505 | } 506 | .leading-tight { 507 | line-height: 1.25; 508 | } 509 | .tracking-tight { 510 | letter-spacing: -0.025em; 511 | } 512 | .text-green-500 { 513 | --tw-text-opacity: 1; 514 | color: rgb(34 197 94 / var(--tw-text-opacity)); 515 | } 516 | .text-blue-500 { 517 | --tw-text-opacity: 1; 518 | color: rgb(59 130 246 / var(--tw-text-opacity)); 519 | } 520 | .hover\:text-blue-600:hover { 521 | --tw-text-opacity: 1; 522 | color: rgb(37 99 235 / var(--tw-text-opacity)); 523 | } 524 | @media (min-width: 640px) { 525 | 526 | .sm\:max-w-sm { 527 | max-width: 24rem; 528 | } 529 | 530 | .sm\:px-20 { 531 | padding-left: 5rem; 532 | padding-right: 5rem; 533 | } 534 | 535 | .sm\:text-5xl { 536 | font-size: 3rem; 537 | line-height: 1; 538 | } 539 | 540 | .sm\:text-3xl { 541 | font-size: 1.875rem; 542 | line-height: 2.25rem; 543 | } 544 | } 545 | @media (min-width: 768px) { 546 | 547 | .md\:px-32 { 548 | padding-left: 8rem; 549 | padding-right: 8rem; 550 | } 551 | } 552 | @media (min-width: 1024px) { 553 | 554 | .lg\:order-1 { 555 | order: 1; 556 | } 557 | 558 | .lg\:mb-0 { 559 | margin-bottom: 0px; 560 | } 561 | 562 | .lg\:w-1\/2 { 563 | width: 50%; 564 | } 565 | 566 | .lg\:max-w-md { 567 | max-width: 28rem; 568 | } 569 | 570 | .lg\:max-w-full { 571 | max-width: 100%; 572 | } 573 | 574 | .lg\:px-16 { 575 | padding-left: 4rem; 576 | padding-right: 4rem; 577 | } 578 | } 579 | @media (min-width: 1280px) { 580 | 581 | .xl\:mb-6 { 582 | margin-bottom: 1.5rem; 583 | } 584 | 585 | .xl\:mt-6 { 586 | margin-top: 1.5rem; 587 | } 588 | } -------------------------------------------------------------------------------- /examples/dark-with-media/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: 'media', 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | }, 13 | colors: { 14 | red: { 15 | 50: '#ff3232', 16 | 500: '#ff0000', 17 | 900: '#d70000', 18 | }, 19 | }, 20 | }, 21 | '.container': { 22 | sizes: { 23 | medium: '1.5rem', 24 | container: '2rem', 25 | }, 26 | }, 27 | }), 28 | darkVariables: (theme) => ({ 29 | DEFAULT: { 30 | colors: { 31 | red: { 32 | 50: '#c665ff', 33 | 500: '#9433f1', 34 | 900: '#6c0bc9', 35 | }, 36 | }, 37 | }, 38 | '.container': { 39 | colors: { 40 | red: { 41 | 50: '#ff0000', 42 | }, 43 | }, 44 | }, 45 | }), 46 | }, 47 | plugins: [require('../../src/index')], 48 | } 49 | -------------------------------------------------------------------------------- /examples/dark-with-media/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/prefix/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --prefix-sizes-small: 1rem; 3 | --prefix-sizes-medium: 2rem; 4 | --prefix-sizes-large: 3rem; 5 | --prefix-colors-red-50: #ff3232; 6 | --prefix-colors-red-500: #ff0000; 7 | --prefix-colors-red-900: #d70000 8 | } 9 | .container { 10 | --prefix-sizes-medium: 1.5rem; 11 | --prefix-sizes-container: 2rem 12 | } -------------------------------------------------------------------------------- /examples/prefix/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/prefix/image.png -------------------------------------------------------------------------------- /examples/prefix/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | variablePrefix example using @mertasan/tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [variablePrefix example] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/prefix/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prefix", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/prefix/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --prefix-sizes-small: 1rem; 373 | --prefix-sizes-medium: 2rem; 374 | --prefix-sizes-large: 3rem; 375 | --prefix-colors-red-50: #ff3232; 376 | --prefix-colors-red-500: #ff0000; 377 | --prefix-colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --prefix-sizes-medium: 1.5rem; 382 | --prefix-sizes-container: 2rem; 383 | width: 100%; 384 | } 385 | @media (min-width: 640px) { 386 | 387 | .container { 388 | max-width: 640px; 389 | } 390 | } 391 | @media (min-width: 768px) { 392 | 393 | .container { 394 | max-width: 768px; 395 | } 396 | } 397 | @media (min-width: 1024px) { 398 | 399 | .container { 400 | max-width: 1024px; 401 | } 402 | } 403 | @media (min-width: 1280px) { 404 | 405 | .container { 406 | max-width: 1280px; 407 | } 408 | } 409 | @media (min-width: 1536px) { 410 | 411 | .container { 412 | max-width: 1536px; 413 | } 414 | } 415 | .order-1 { 416 | order: 1; 417 | } 418 | .mx-auto { 419 | margin-left: auto; 420 | margin-right: auto; 421 | } 422 | .-mx-3 { 423 | margin-left: -0.75rem; 424 | margin-right: -0.75rem; 425 | } 426 | .mb-4 { 427 | margin-bottom: 1rem; 428 | } 429 | .mt-4 { 430 | margin-top: 1rem; 431 | } 432 | .mb-12 { 433 | margin-bottom: 3rem; 434 | } 435 | .flex { 436 | display: flex; 437 | } 438 | .w-full { 439 | width: 100%; 440 | } 441 | .max-w-6xl { 442 | max-width: 72rem; 443 | } 444 | .flex-wrap { 445 | flex-wrap: wrap; 446 | } 447 | .items-center { 448 | align-items: center; 449 | } 450 | .bg-gray-50 { 451 | --tw-bg-opacity: 1; 452 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 453 | } 454 | .py-20 { 455 | padding-top: 5rem; 456 | padding-bottom: 5rem; 457 | } 458 | .px-4 { 459 | padding-left: 1rem; 460 | padding-right: 1rem; 461 | } 462 | .px-10 { 463 | padding-left: 2.5rem; 464 | padding-right: 2.5rem; 465 | } 466 | .px-3 { 467 | padding-left: 0.75rem; 468 | padding-right: 0.75rem; 469 | } 470 | .text-3xl { 471 | font-size: 1.875rem; 472 | line-height: 2.25rem; 473 | } 474 | .text-2xl { 475 | font-size: 1.5rem; 476 | line-height: 2rem; 477 | } 478 | .text-base { 479 | font-size: 1rem; 480 | line-height: 1.5rem; 481 | } 482 | .font-bold { 483 | font-weight: 700; 484 | } 485 | .font-semibold { 486 | font-weight: 600; 487 | } 488 | .font-medium { 489 | font-weight: 500; 490 | } 491 | .leading-tight { 492 | line-height: 1.25; 493 | } 494 | .tracking-tight { 495 | letter-spacing: -0.025em; 496 | } 497 | .text-green-500 { 498 | --tw-text-opacity: 1; 499 | color: rgb(34 197 94 / var(--tw-text-opacity)); 500 | } 501 | .text-blue-500 { 502 | --tw-text-opacity: 1; 503 | color: rgb(59 130 246 / var(--tw-text-opacity)); 504 | } 505 | .hover\:text-blue-600:hover { 506 | --tw-text-opacity: 1; 507 | color: rgb(37 99 235 / var(--tw-text-opacity)); 508 | } 509 | @media (min-width: 640px) { 510 | 511 | .sm\:max-w-sm { 512 | max-width: 24rem; 513 | } 514 | 515 | .sm\:px-20 { 516 | padding-left: 5rem; 517 | padding-right: 5rem; 518 | } 519 | 520 | .sm\:text-5xl { 521 | font-size: 3rem; 522 | line-height: 1; 523 | } 524 | 525 | .sm\:text-3xl { 526 | font-size: 1.875rem; 527 | line-height: 2.25rem; 528 | } 529 | } 530 | @media (min-width: 768px) { 531 | 532 | .md\:px-32 { 533 | padding-left: 8rem; 534 | padding-right: 8rem; 535 | } 536 | } 537 | @media (min-width: 1024px) { 538 | 539 | .lg\:order-1 { 540 | order: 1; 541 | } 542 | 543 | .lg\:mb-0 { 544 | margin-bottom: 0px; 545 | } 546 | 547 | .lg\:w-1\/2 { 548 | width: 50%; 549 | } 550 | 551 | .lg\:max-w-md { 552 | max-width: 28rem; 553 | } 554 | 555 | .lg\:max-w-full { 556 | max-width: 100%; 557 | } 558 | 559 | .lg\:px-16 { 560 | padding-left: 4rem; 561 | padding-right: 4rem; 562 | } 563 | } 564 | @media (min-width: 1280px) { 565 | 566 | .xl\:mb-6 { 567 | margin-bottom: 1.5rem; 568 | } 569 | 570 | .xl\:mt-6 { 571 | margin-top: 1.5rem; 572 | } 573 | } -------------------------------------------------------------------------------- /examples/prefix/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: 'class', 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | }, 13 | colors: { 14 | red: { 15 | 50: '#ff3232', 16 | 500: '#ff0000', 17 | 900: '#d70000', 18 | }, 19 | }, 20 | }, 21 | '.container': { 22 | sizes: { 23 | medium: '1.5rem', 24 | container: '2rem', 25 | }, 26 | }, 27 | }), 28 | }, 29 | plugins: [ 30 | require('../../src/index')({ 31 | variablePrefix: '--prefix', 32 | }), 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /examples/prefix/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/simple/clean.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --sizes-0\.5: 2px; 6 | --sizes-1\.0-foo: 1rem; 7 | --sizes-1\.0-2\.4: 2rem; 8 | --colors-red-50: #ff3232; 9 | --colors-red-500: #ff0000; 10 | --colors-red-900: #d70000 11 | } 12 | 13 | .container { 14 | --sizes-medium: 1.5rem; 15 | --sizes-container: 2rem 16 | } 17 | -------------------------------------------------------------------------------- /examples/simple/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/simple/image.png -------------------------------------------------------------------------------- /examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Simple example using @mertasan/tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Tailwindcss Variables 17 | 18 | [simple example] 19 | 20 | source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/simple/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.0.0 | MIT License | https://tailwindcss.com 3 | *//* 4 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 5 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; /* 1 */ 12 | border-width: 0; /* 2 */ 13 | border-style: solid; /* 2 */ 14 | border-color: currentColor; /* 2 */ 15 | } 16 | 17 | ::before, 18 | ::after { 19 | --tw-content: ''; 20 | } 21 | 22 | /* 23 | 1. Use a consistent sensible line-height in all browsers. 24 | 2. Prevent adjustments of font size after orientation changes in iOS. 25 | 3. Use a more readable tab size. 26 | 4. Use the user's configured `sans` font-family by default. 27 | */ 28 | 29 | html { 30 | line-height: 1.5; /* 1 */ 31 | -webkit-text-size-adjust: 100%; /* 2 */ /* 3 */ 32 | tab-size: 4; /* 3 */ 33 | font-family: 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"; /* 4 */ 34 | } 35 | 36 | /* 37 | 1. Remove the margin in all browsers. 38 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 39 | */ 40 | 41 | body { 42 | margin: 0; /* 1 */ 43 | line-height: inherit; /* 2 */ 44 | } 45 | 46 | /* 47 | 1. Add the correct height in Firefox. 48 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 49 | 3. Ensure horizontal rules are visible by default. 50 | */ 51 | 52 | hr { 53 | height: 0; /* 1 */ 54 | color: inherit; /* 2 */ 55 | border-top-width: 1px; /* 3 */ 56 | } 57 | 58 | /* 59 | Add the correct text decoration in Chrome, Edge, and Safari. 60 | */ 61 | 62 | abbr[title] { 63 | -webkit-text-decoration: underline dotted; 64 | text-decoration: underline dotted; 65 | } 66 | 67 | /* 68 | Remove the default font size and weight for headings. 69 | */ 70 | 71 | h1, 72 | h2, 73 | h3, 74 | h4, 75 | h5, 76 | h6 { 77 | font-size: inherit; 78 | font-weight: inherit; 79 | } 80 | 81 | /* 82 | Reset links to optimize for opt-in styling instead of opt-out. 83 | */ 84 | 85 | a { 86 | color: inherit; 87 | text-decoration: inherit; 88 | } 89 | 90 | /* 91 | Add the correct font weight in Edge and Safari. 92 | */ 93 | 94 | b, 95 | strong { 96 | font-weight: bolder; 97 | } 98 | 99 | /* 100 | 1. Use the user's configured `mono` font family by default. 101 | 2. Correct the odd `em` font sizing in all browsers. 102 | */ 103 | 104 | code, 105 | kbd, 106 | samp, 107 | pre { 108 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /* 113 | Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /* 121 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 122 | */ 123 | 124 | sub, 125 | sup { 126 | font-size: 75%; 127 | line-height: 0; 128 | position: relative; 129 | vertical-align: baseline; 130 | } 131 | 132 | sub { 133 | bottom: -0.25em; 134 | } 135 | 136 | sup { 137 | top: -0.5em; 138 | } 139 | 140 | /* 141 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 142 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 143 | 3. Remove gaps between table borders by default. 144 | */ 145 | 146 | table { 147 | text-indent: 0; /* 1 */ 148 | border-color: inherit; /* 2 */ 149 | border-collapse: collapse; /* 3 */ 150 | } 151 | 152 | /* 153 | 1. Change the font styles in all browsers. 154 | 2. Remove the margin in Firefox and Safari. 155 | 3. Remove default padding in all browsers. 156 | */ 157 | 158 | button, 159 | input, 160 | optgroup, 161 | select, 162 | textarea { 163 | font-family: inherit; /* 1 */ 164 | font-size: 100%; /* 1 */ 165 | line-height: inherit; /* 1 */ 166 | color: inherit; /* 1 */ 167 | margin: 0; /* 2 */ 168 | padding: 0; /* 3 */ 169 | } 170 | 171 | /* 172 | Remove the inheritance of text transform in Edge and Firefox. 173 | */ 174 | 175 | button, 176 | select { 177 | text-transform: none; 178 | } 179 | 180 | /* 181 | 1. Correct the inability to style clickable types in iOS and Safari. 182 | 2. Remove default button styles. 183 | */ 184 | 185 | button, 186 | [type='button'], 187 | [type='reset'], 188 | [type='submit'] { 189 | -webkit-appearance: button; /* 1 */ 190 | background-color: transparent; /* 2 */ 191 | background-image: none; /* 2 */ 192 | } 193 | 194 | /* 195 | Use the modern Firefox focus style for all focusable elements. 196 | */ 197 | 198 | :-moz-focusring { 199 | outline: auto; 200 | } 201 | 202 | /* 203 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 204 | */ 205 | 206 | :-moz-ui-invalid { 207 | box-shadow: none; 208 | } 209 | 210 | /* 211 | Add the correct vertical alignment in Chrome and Firefox. 212 | */ 213 | 214 | progress { 215 | vertical-align: baseline; 216 | } 217 | 218 | /* 219 | Correct the cursor style of increment and decrement buttons in Safari. 220 | */ 221 | 222 | ::-webkit-inner-spin-button, 223 | ::-webkit-outer-spin-button { 224 | height: auto; 225 | } 226 | 227 | /* 228 | 1. Correct the odd appearance in Chrome and Safari. 229 | 2. Correct the outline style in Safari. 230 | */ 231 | 232 | [type='search'] { 233 | -webkit-appearance: textfield; /* 1 */ 234 | outline-offset: -2px; /* 2 */ 235 | } 236 | 237 | /* 238 | Remove the inner padding in Chrome and Safari on macOS. 239 | */ 240 | 241 | ::-webkit-search-decoration { 242 | -webkit-appearance: none; 243 | } 244 | 245 | /* 246 | 1. Correct the inability to style clickable types in iOS and Safari. 247 | 2. Change font properties to `inherit` in Safari. 248 | */ 249 | 250 | ::-webkit-file-upload-button { 251 | -webkit-appearance: button; /* 1 */ 252 | font: inherit; /* 2 */ 253 | } 254 | 255 | /* 256 | Add the correct display in Chrome and Safari. 257 | */ 258 | 259 | summary { 260 | display: list-item; 261 | } 262 | 263 | /* 264 | Removes the default spacing and border for appropriate elements. 265 | */ 266 | 267 | blockquote, 268 | dl, 269 | dd, 270 | h1, 271 | h2, 272 | h3, 273 | h4, 274 | h5, 275 | h6, 276 | hr, 277 | figure, 278 | p, 279 | pre { 280 | margin: 0; 281 | } 282 | 283 | fieldset { 284 | margin: 0; 285 | padding: 0; 286 | } 287 | 288 | legend { 289 | padding: 0; 290 | } 291 | 292 | ol, 293 | ul, 294 | menu { 295 | list-style: none; 296 | margin: 0; 297 | padding: 0; 298 | } 299 | 300 | /* 301 | Prevent resizing textareas horizontally by default. 302 | */ 303 | 304 | textarea { 305 | resize: vertical; 306 | } 307 | 308 | /* 309 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 310 | 2. Set the default placeholder color to the user's configured gray 400 color. 311 | */ 312 | 313 | input::placeholder, 314 | textarea::placeholder { 315 | opacity: 1; /* 1 */ 316 | color: #9ca3af; /* 2 */ 317 | } 318 | 319 | /* 320 | Set the default cursor for buttons. 321 | */ 322 | 323 | button, 324 | [role="button"] { 325 | cursor: pointer; 326 | } 327 | 328 | /* 329 | Make sure disabled buttons don't get the pointer cursor. 330 | */ 331 | :disabled { 332 | cursor: default; 333 | } 334 | 335 | /* 336 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 337 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 338 | This can trigger a poorly considered lint error in some tools but is included by design. 339 | */ 340 | 341 | img, 342 | svg, 343 | video, 344 | canvas, 345 | audio, 346 | iframe, 347 | embed, 348 | object { 349 | display: block; /* 1 */ 350 | vertical-align: middle; /* 2 */ 351 | } 352 | 353 | /* 354 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 355 | */ 356 | 357 | img, 358 | video { 359 | max-width: 100%; 360 | height: auto; 361 | } 362 | 363 | /* 364 | Ensure the default browser behavior of the `hidden` attribute. 365 | */ 366 | 367 | [hidden] { 368 | display: none; 369 | } 370 | 371 | :root { 372 | --sizes-small: 1rem; 373 | --sizes-medium: 2rem; 374 | --sizes-large: 3rem; 375 | --colors-red-50: #ff3232; 376 | --colors-red-500: #ff0000; 377 | --colors-red-900: #d70000; 378 | } 379 | 380 | .container { 381 | --sizes-medium: 1.5rem; 382 | --sizes-container: 2rem; 383 | width: 100%; 384 | } 385 | @media (min-width: 640px) { 386 | 387 | .container { 388 | max-width: 640px; 389 | } 390 | } 391 | @media (min-width: 768px) { 392 | 393 | .container { 394 | max-width: 768px; 395 | } 396 | } 397 | @media (min-width: 1024px) { 398 | 399 | .container { 400 | max-width: 1024px; 401 | } 402 | } 403 | @media (min-width: 1280px) { 404 | 405 | .container { 406 | max-width: 1280px; 407 | } 408 | } 409 | @media (min-width: 1536px) { 410 | 411 | .container { 412 | max-width: 1536px; 413 | } 414 | } 415 | .order-1 { 416 | order: 1; 417 | } 418 | .mx-auto { 419 | margin-left: auto; 420 | margin-right: auto; 421 | } 422 | .-mx-3 { 423 | margin-left: -0.75rem; 424 | margin-right: -0.75rem; 425 | } 426 | .mb-4 { 427 | margin-bottom: 1rem; 428 | } 429 | .mt-4 { 430 | margin-top: 1rem; 431 | } 432 | .mb-12 { 433 | margin-bottom: 3rem; 434 | } 435 | .flex { 436 | display: flex; 437 | } 438 | .w-full { 439 | width: 100%; 440 | } 441 | .max-w-6xl { 442 | max-width: 72rem; 443 | } 444 | .flex-wrap { 445 | flex-wrap: wrap; 446 | } 447 | .items-center { 448 | align-items: center; 449 | } 450 | .bg-gray-50 { 451 | --tw-bg-opacity: 1; 452 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 453 | } 454 | .py-20 { 455 | padding-top: 5rem; 456 | padding-bottom: 5rem; 457 | } 458 | .px-4 { 459 | padding-left: 1rem; 460 | padding-right: 1rem; 461 | } 462 | .px-10 { 463 | padding-left: 2.5rem; 464 | padding-right: 2.5rem; 465 | } 466 | .px-3 { 467 | padding-left: 0.75rem; 468 | padding-right: 0.75rem; 469 | } 470 | .text-3xl { 471 | font-size: 1.875rem; 472 | line-height: 2.25rem; 473 | } 474 | .text-2xl { 475 | font-size: 1.5rem; 476 | line-height: 2rem; 477 | } 478 | .text-base { 479 | font-size: 1rem; 480 | line-height: 1.5rem; 481 | } 482 | .font-bold { 483 | font-weight: 700; 484 | } 485 | .font-semibold { 486 | font-weight: 600; 487 | } 488 | .font-medium { 489 | font-weight: 500; 490 | } 491 | .leading-tight { 492 | line-height: 1.25; 493 | } 494 | .tracking-tight { 495 | letter-spacing: -0.025em; 496 | } 497 | .text-green-500 { 498 | --tw-text-opacity: 1; 499 | color: rgb(34 197 94 / var(--tw-text-opacity)); 500 | } 501 | .text-blue-500 { 502 | --tw-text-opacity: 1; 503 | color: rgb(59 130 246 / var(--tw-text-opacity)); 504 | } 505 | .hover\:text-blue-600:hover { 506 | --tw-text-opacity: 1; 507 | color: rgb(37 99 235 / var(--tw-text-opacity)); 508 | } 509 | @media (min-width: 640px) { 510 | 511 | .sm\:max-w-sm { 512 | max-width: 24rem; 513 | } 514 | 515 | .sm\:px-20 { 516 | padding-left: 5rem; 517 | padding-right: 5rem; 518 | } 519 | 520 | .sm\:text-5xl { 521 | font-size: 3rem; 522 | line-height: 1; 523 | } 524 | 525 | .sm\:text-3xl { 526 | font-size: 1.875rem; 527 | line-height: 2.25rem; 528 | } 529 | } 530 | @media (min-width: 768px) { 531 | 532 | .md\:px-32 { 533 | padding-left: 8rem; 534 | padding-right: 8rem; 535 | } 536 | } 537 | @media (min-width: 1024px) { 538 | 539 | .lg\:order-1 { 540 | order: 1; 541 | } 542 | 543 | .lg\:mb-0 { 544 | margin-bottom: 0px; 545 | } 546 | 547 | .lg\:w-1\/2 { 548 | width: 50%; 549 | } 550 | 551 | .lg\:max-w-md { 552 | max-width: 28rem; 553 | } 554 | 555 | .lg\:max-w-full { 556 | max-width: 100%; 557 | } 558 | 559 | .lg\:px-16 { 560 | padding-left: 4rem; 561 | padding-right: 4rem; 562 | } 563 | } 564 | @media (min-width: 1280px) { 565 | 566 | .xl\:mb-6 { 567 | margin-bottom: 1.5rem; 568 | } 569 | 570 | .xl\:mt-6 { 571 | margin-top: 1.5rem; 572 | } 573 | } -------------------------------------------------------------------------------- /examples/simple/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | darkMode: 'class', 5 | theme: { 6 | variables: (theme) => ({ 7 | DEFAULT: { 8 | sizes: { 9 | small: '1rem', 10 | medium: '2rem', 11 | large: '3rem', 12 | '0.5': '2px', 13 | '1.0': { 14 | foo: '1rem', 15 | 2.4: '2rem', 16 | }, 17 | }, 18 | colors: { 19 | red: { 20 | 50: '#ff3232', 21 | 500: '#ff0000', 22 | 900: '#d70000', 23 | }, 24 | }, 25 | }, 26 | '.container': { 27 | sizes: { 28 | medium: '1.5rem', 29 | container: '2rem', 30 | }, 31 | }, 32 | }), 33 | }, 34 | plugins: [require('../../src/index')], 35 | } 36 | -------------------------------------------------------------------------------- /examples/simple/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/use-host/clean.css: -------------------------------------------------------------------------------- 1 | :host { 2 | --sizes-small: 1rem; 3 | --sizes-medium: 2rem; 4 | --sizes-large: 3rem; 5 | --sizes-0\.5: 2px; 6 | --sizes-1\.0-foo: 1rem; 7 | --sizes-1\.0-2\.4: 2rem; 8 | --colors-red-50: #ff3232; 9 | --colors-red-500: #ff0000; 10 | --colors-red-900: #d70000 11 | } 12 | 13 | .container { 14 | --sizes-medium: 1.5rem; 15 | --sizes-container: 2rem 16 | } 17 | -------------------------------------------------------------------------------- /examples/use-host/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mertasan/tailwindcss-variables/0743d8bb1a282afde538c82afe17b975efad1a46/examples/use-host/image.png -------------------------------------------------------------------------------- /examples/use-host/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Use host example using @mertasan/tailwindcss-variables 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Tailwindcss Variables 16 | 17 | [simple example] 18 | 19 | source 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /examples/use-host/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-host", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "env NODE_ENV=production npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./style.css", 6 | "build:clean": "env NODE_ENV=production CLEAN=true npx tailwindcss build ./tailwind.css -c ./tailwind.config.js -o ./clean.css" 7 | }, 8 | "devDependencies": { 9 | "@mertasan/tailwindcss-variables": "latest", 10 | "autoprefixer": "^10.4.0", 11 | "postcss": "^8.4.4", 12 | "tailwindcss": "^3.0.11" 13 | }, 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/use-host/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html'], 3 | corePlugins: process.env.CLEAN ? [] : {}, 4 | theme: { 5 | variables: (theme) => ({ 6 | DEFAULT: { 7 | sizes: { 8 | small: '1rem', 9 | medium: '2rem', 10 | large: '3rem', 11 | '0.5': '2px', 12 | '1.0': { 13 | foo: '1rem', 14 | 2.4: '2rem', 15 | }, 16 | }, 17 | colors: { 18 | red: { 19 | 50: '#ff3232', 20 | 500: '#ff0000', 21 | 900: '#d70000', 22 | }, 23 | }, 24 | }, 25 | '.container': { 26 | sizes: { 27 | medium: '1.5rem', 28 | container: '2rem', 29 | }, 30 | }, 31 | }), 32 | }, 33 | plugins: [require('../../src/index')({ 34 | useHost: true 35 | })], 36 | } 37 | -------------------------------------------------------------------------------- /examples/use-host/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mertasan/tailwindcss-variables", 3 | "version": "2.7.0", 4 | "description": "Easily create css variables without the need for a css file!", 5 | "main": "src/index.js", 6 | "license": "MIT", 7 | "repository": "https://github.com/mertasan/tailwindcss-variables", 8 | "bugs": { 9 | "url": "https://github.com/mertasan/tailwindcss-variables/issues" 10 | }, 11 | "homepage": "https://github.com/mertasan/tailwindcss-variables", 12 | "author": "Mert Aşan (https://github.com/mertasan)", 13 | "publishConfig": { 14 | "access": "public" 15 | }, 16 | "scripts": { 17 | "test": "jest", 18 | "test:update-snapshots": "jest -u", 19 | "test:coverage": "jest --coverage", 20 | "build": "env NODE_ENV=production node scripts/build.js", 21 | "build:clean": "env NODE_ENV=production CLEAN=true node scripts/build.js", 22 | "style": "eslint .", 23 | "lint": "npm run style", 24 | "format": "prettier --write ." 25 | }, 26 | "keywords": [ 27 | "tailwindcss", 28 | "tailwindcss variables", 29 | "tailwind variables", 30 | "css variables", 31 | "tailwind css variables", 32 | "tailwindcss css variables", 33 | "tailwindcss dark mode", 34 | "tailwindcss multi theme" 35 | ], 36 | "dependencies": { 37 | "lodash": "^4.17.21" 38 | }, 39 | "devDependencies": { 40 | "autoprefixer": "^10.4.13", 41 | "cross-env": "^7.0.3", 42 | "eslint": "^8.23.1", 43 | "eslint-config-prettier": "^8.5.0", 44 | "eslint-plugin-prettier": "^4.2.1", 45 | "fs-extra": "^10.0.0", 46 | "jest": "^29.4.3", 47 | "postcss": "^8.4.21", 48 | "postcss-import": "^14.1.0", 49 | "prettier": "^2.5.0", 50 | "snapshot-diff": "^0.10.0", 51 | "tailwindcss": "^3.2.7" 52 | }, 53 | "peerDependencies": { 54 | "autoprefixer": "^10.0.2", 55 | "postcss": "^8.0.9" 56 | }, 57 | "prettier": { 58 | "semi": false, 59 | "singleQuote": true, 60 | "printWidth": 120, 61 | "tabWidth": 2, 62 | "useTabs": false, 63 | "trailingComma": "es5", 64 | "bracketSpacing": true, 65 | "parser": "flow", 66 | "overrides": [ 67 | { 68 | "files": [ 69 | "**/*.css", 70 | "**/*.scss", 71 | "**/*.html" 72 | ], 73 | "options": { 74 | "singleQuote": false 75 | } 76 | } 77 | ] 78 | }, 79 | "jest": { 80 | "testTimeout": 30000, 81 | "testMatch": [ 82 | "/__tests__/**/*.test.js" 83 | ], 84 | "collectCoverageFrom": [ 85 | "src/**/*.js", 86 | "!**/node_modules/**" 87 | ], 88 | "testPathIgnorePatterns": [ 89 | "/__tests__/util/" 90 | ], 91 | "collectCoverage": true, 92 | "coverageReporters": [ 93 | "json", 94 | "html" 95 | ] 96 | }, 97 | "browserslist": [ 98 | "> 1%", 99 | "not edge <= 18", 100 | "not ie 11", 101 | "not op_mini all" 102 | ], 103 | "engines": { 104 | "node": ">=12.13.0" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const postcss = require('postcss') 3 | const tailwind = require('tailwindcss') 4 | 5 | function buildDistFile(examplePath, message) { 6 | console.info('Building: ' + message + '...') 7 | 8 | let styleFilename = 'style' 9 | if (process.env.CLEAN) { 10 | styleFilename = 'clean' 11 | } 12 | return postcss([ 13 | tailwind({ 14 | ...require('../' + examplePath + '/tailwind.config'), 15 | content: ['./' + examplePath + '/*.html'], 16 | }), 17 | require('autoprefixer'), 18 | ]) 19 | .process(['@tailwind base;', '@tailwind components;', '@tailwind utilities;'].join('\n'), { 20 | from: undefined, 21 | to: `./${examplePath}/${styleFilename}.css`, 22 | map: false, 23 | }) 24 | .then((result) => { 25 | fs.writeFileSync(`./${examplePath}/${styleFilename}.css`, result.css) 26 | return result 27 | }) 28 | .catch((error) => { 29 | console.log(error) 30 | }) 31 | } 32 | 33 | console.info('Building...') 34 | 35 | Promise.all([ 36 | buildDistFile('examples/simple', 'Examples -> simple'), 37 | buildDistFile('examples/prefix', 'Examples -> prefix'), 38 | buildDistFile('examples/dark-custom-selector', 'Examples -> dark-custom-selector'), 39 | buildDistFile('examples/dark-with-class', 'Examples -> dark-with-class'), 40 | buildDistFile('examples/dark-with-class-to-root', 'Examples -> dark-with-class-to-root'), 41 | buildDistFile('examples/dark-with-media', 'Examples -> dark-with-media'), 42 | buildDistFile('examples/color-variable-helper', 'Examples -> color-variable-helper'), 43 | ]).then(() => { 44 | console.log('Finished building.') 45 | }) 46 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | const startsWith = require('lodash/startsWith') 2 | const mapValues = require('lodash/mapValues') 3 | const isPlainObject = require('lodash/isPlainObject') 4 | const includes = require('lodash/includes') 5 | 6 | const withFallback = (variable, startsWithVar = false) => { 7 | if (includes(variable, ',')) { 8 | variable = variable.replace(',', '-rgb,') 9 | return startsWithVar ? variable : variable + ')' 10 | } else { 11 | return startsWithVar ? variable.replace(')', '-rgb)') : variable + '-rgb' 12 | } 13 | } 14 | const withRgb = (variable, forceRGB) => { 15 | if (forceRGB) { 16 | return startsWith(variable, 'var') ? variable : 'var(' + variable + ')' 17 | } 18 | return startsWith(variable, 'var') ? withFallback(variable, true) : 'var(' + withFallback(variable) + ')' 19 | } 20 | 21 | const colorVariable = (variable, forceRGB = false) => { 22 | return function ({ opacityVariable, opacityValue }) { 23 | if (opacityValue !== undefined) { 24 | return `rgba(${withRgb(variable, forceRGB)}, ${opacityValue})` 25 | } 26 | if (opacityVariable !== undefined) { 27 | return `rgba(${withRgb(variable, forceRGB)}, var(${opacityVariable}, 1))` 28 | } 29 | return `rgb(${withRgb(variable, forceRGB)})` 30 | } 31 | } 32 | 33 | const setColorVariable = (color, forceRGB) => { 34 | return startsWith(color, 'var') ? colorVariable(color, forceRGB) : color 35 | } 36 | const convertColorVariables = (colors, forceRGB) => { 37 | return mapValues(colors, (color) => 38 | isPlainObject(color) 39 | ? mapValues(color, (subColor) => setColorVariable(subColor, forceRGB)) 40 | : setColorVariable(color, forceRGB) 41 | ) 42 | } 43 | 44 | module.exports.colorVariable = colorVariable 45 | module.exports.convertColorVariables = convertColorVariables 46 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require('tailwindcss/plugin') 2 | const isEmpty = require('lodash/isEmpty') 3 | const isUndefined = require('lodash/isUndefined') 4 | const api = require('./pluginApi') 5 | const has = require('lodash/has') 6 | const get = require('lodash/get') 7 | const { convertColorVariables } = require('./helpers') 8 | 9 | /** 10 | * @typedef pluginOptions 11 | * @property {Boolean} darkToRoot 12 | * @property {Boolean} useHost 13 | * @property {Object} extendColors 14 | * @property {Boolean} forceRGB 15 | * @property {Boolean} toBase 16 | * @property {Boolean} colorVariables 17 | * @property {String} variablePrefix 18 | * @property {String} darkSelector - @deprecated 19 | */ 20 | 21 | /** 22 | * @typedef {Object} plugin 23 | * @property {function} withOptions 24 | */ 25 | 26 | module.exports = plugin.withOptions( 27 | /** 28 | * @param {pluginOptions} options 29 | */ 30 | function (options) { 31 | return function ({ addBase, addComponents, theme, config }) { 32 | let variables = theme('variables', {}) 33 | let darkVariables = theme('darkVariables', {}) 34 | let toBase = get(options, 'toBase', true) 35 | if (!isEmpty(variables)) { 36 | let getVariables = api.variables(variables, options) 37 | toBase ? addBase(getVariables) : addComponents(getVariables) 38 | } 39 | 40 | if (isUndefined(options)) { 41 | options = {} 42 | } 43 | 44 | let [mode, darkSelector = get(options, 'darkSelector', '.dark') ?? '.dark'] = [].concat( 45 | config('darkMode', 'media') 46 | ) 47 | 48 | options.darkSelector = darkSelector 49 | 50 | if (!isEmpty(darkVariables) && ['class', 'media'].includes(mode)) { 51 | let getDarkVariables = api.darkVariables(darkVariables, options, mode) 52 | toBase ? addBase(getDarkVariables) : addComponents(getDarkVariables) 53 | } 54 | } 55 | }, 56 | (options) => ({ 57 | theme: { 58 | extend: { 59 | colors: has(options, 'extendColors') 60 | ? convertColorVariables(options.extendColors, options.forceRGB ? options.forceRGB : false) 61 | : {}, 62 | }, 63 | }, 64 | }) 65 | ) 66 | -------------------------------------------------------------------------------- /src/pluginApi.js: -------------------------------------------------------------------------------- 1 | const fromPairs = require('lodash/fromPairs') 2 | const toPairs = require('lodash/toPairs') 3 | const merge = require('lodash/merge') 4 | const isEmpty = require('lodash/isEmpty') 5 | const _forEach = require('lodash/forEach') 6 | const has = require('lodash/has') 7 | const { setVariable, setDarkMediaVariable, setComponent, build, darkBuild, flattenOptions } = require('./utils') 8 | 9 | const variables = (variables, options) => { 10 | let variableList = {} 11 | let data = build(options, variables) 12 | 13 | _forEach(data, (value, key) => merge(variableList, setVariable(key, fromPairs(value)))) 14 | 15 | return variableList 16 | } 17 | 18 | const darkVariables = (variables, options, darkMode = 'media') => { 19 | let variableList = {} 20 | 21 | if (darkMode === 'class' || darkMode === 'media') { 22 | if (!has(options, 'darkSelector')) { 23 | options.darkSelector = '.dark' 24 | } 25 | let data = darkBuild(options, darkMode, variables) 26 | _forEach(data, (value, key) => 27 | merge( 28 | variableList, 29 | darkMode === 'media' ? setDarkMediaVariable(key, fromPairs(value)) : setVariable(key, fromPairs(value)) 30 | ) 31 | ) 32 | } 33 | 34 | return variableList 35 | } 36 | 37 | const getComponents = (selector, components) => { 38 | let componentList = {} 39 | selector = isEmpty(selector) ? '' : selector 40 | toPairs(flattenOptions(components)).forEach(([key, config]) => { 41 | const modifier = key === 'DEFAULT' ? '' : isEmpty(selector) ? `${key}` : `-${key}` 42 | toPairs(config) 43 | .filter(([, options]) => !isEmpty(options)) 44 | .forEach(([subKey, options]) => merge(componentList, setComponent(selector, modifier, options))) 45 | }) 46 | 47 | return componentList 48 | } 49 | module.exports.getComponents = getComponents 50 | module.exports.variables = variables 51 | module.exports.darkVariables = darkVariables 52 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const merge = require('lodash/merge') 2 | const fromPairs = require('lodash/fromPairs') 3 | const toPairs = require('lodash/toPairs') 4 | const assign = require('lodash/assign') 5 | const entries = require('lodash/entries') 6 | const indexOf = require('lodash/indexOf') 7 | const isPlainObject = require('lodash/isPlainObject') 8 | const hasOwn = require('lodash/has') 9 | const _forEach = require('lodash/forEach') 10 | const _replace = require('lodash/replace') 11 | const startsWith = require('lodash/startsWith') 12 | const trimStart = require('lodash/trimStart') 13 | const trimEnd = require('lodash/trimEnd') 14 | const get = require('lodash/get') 15 | 16 | const setComponent = (component, modifier, options) => { 17 | return { [`${component}${modifier}`]: options } 18 | } 19 | 20 | const setVariable = (themeName, options) => { 21 | return { [`${themeName}`]: options } 22 | } 23 | const setDarkMediaVariable = (themeName, options) => { 24 | return { 25 | ['@media (prefers-color-scheme: dark)']: { 26 | [`${themeName}`]: options, 27 | }, 28 | } 29 | } 30 | 31 | const flattenOptions = (options) => { 32 | return merge( 33 | {}, 34 | ...toPairs(options).map(([keys, value]) => { 35 | const flattenValue = isPlainObject(value) ? flattenOptions(value) : value 36 | return fromPairs(keys.split(', ').map((key) => [key, flattenValue])) 37 | }) 38 | ) 39 | } 40 | 41 | const formatVariableKey = (key) => { 42 | if (key === 'DEFAULT') { 43 | return '' 44 | } 45 | key = key.toString() 46 | return key 47 | .replace(/_/g, '-') 48 | .replace(/[^a-zA-Z0-9-.]+/gi, '') 49 | .replace(/\./gi, '\\.') 50 | .replace('---', '--') 51 | } 52 | 53 | const splitVars = (source) => { 54 | let results = {} 55 | 56 | ;(function recurse(obj, current) { 57 | for (let key in obj) { 58 | let newKey = formatVariableKey(current ? current + '-' + key : key) 59 | if (indexOf(obj, key) && isPlainObject(obj[key])) { 60 | recurse(value, newKey) 61 | } else { 62 | results[newKey] = obj[key] 63 | } 64 | } 65 | })(source) 66 | return entries(results) 67 | } 68 | 69 | const parseVariables = (object, varPrefix) => { 70 | let newObject = {} 71 | let results = [] 72 | 73 | function recurse(object, varPrefix) { 74 | for (let key in object) { 75 | let pre = _replace(varPrefix === undefined ? '' : varPrefix + '-', '---', '--') 76 | let formattedKey = formatVariableKey(key) 77 | if (hasOwn(object, key) && isPlainObject(object[key])) { 78 | newObject = recurse(object[key], formattedKey ? pre + formattedKey : pre.slice(0, -1)) 79 | } else { 80 | newObject[formattedKey ? pre + formattedKey : pre.slice(0, -1)] = `${object[key]}` 81 | } 82 | } 83 | return newObject 84 | } 85 | 86 | _forEach(splitVars(recurse(object, '--' + varPrefix)), ([key, items]) => results.push([key, items])) 87 | return results 88 | } 89 | 90 | const RGBAtoRGB = (rgba) => { 91 | rgba = trimStart(rgba, 'rgba(') 92 | rgba = trimEnd(rgba, ')') 93 | return rgba.substring(0, rgba.lastIndexOf(',')) 94 | } 95 | 96 | const getRGBKey = (key, forceRGB) => { 97 | if (forceRGB) { 98 | return key 99 | } 100 | if (key === 'DEFAULT') { 101 | return 'rgb' 102 | } else { 103 | return key + '-rgb' 104 | } 105 | } 106 | 107 | const hexToRGB = (key, h, forceRGB) => { 108 | if (startsWith(h, 'rgba')) { 109 | return [getRGBKey(key, forceRGB), RGBAtoRGB(h)] 110 | } else if (startsWith(h, 'rgb')) { 111 | h = trimStart(h, 'rgb(') 112 | h = trimEnd(h, ')') 113 | return [getRGBKey(key, forceRGB), h] 114 | } else if (!startsWith(h, '#')) { 115 | return [key, h] 116 | } 117 | 118 | let r = 0, 119 | g = 0, 120 | b = 0 121 | 122 | // 3 digits 123 | if (h.length === 4) { 124 | r = '0x' + h[1] + h[1] 125 | g = '0x' + h[2] + h[2] 126 | b = '0x' + h[3] + h[3] 127 | 128 | // 6 digits 129 | } else if (h.length === 7) { 130 | r = '0x' + h[1] + h[2] 131 | g = '0x' + h[3] + h[4] 132 | b = '0x' + h[5] + h[6] 133 | } 134 | 135 | return [getRGBKey(key, forceRGB), '' + +r + ',' + +g + ',' + +b + ''] 136 | } 137 | 138 | const setColorVariables = (source, forceRGB) => { 139 | return merge( 140 | source, 141 | ...toPairs(source).map(([keys, value]) => { 142 | const flattenValue = isPlainObject(value) ? setColorVariables(value, forceRGB) : value 143 | return fromPairs(keys.split(', ').map((key) => hexToRGB(key, flattenValue, forceRGB))) 144 | }) 145 | ) 146 | } 147 | 148 | const build = (options, source) => { 149 | let varPrefix = formatVariableKey(get(options, 'variablePrefix', '')) 150 | let colorVariables = get(options, 'colorVariables', false) 151 | let forceRGB = get(options, 'forceRGB', false) 152 | let cssBaseKey = get(options, 'useHost', false) ? `:host` : `:root` 153 | 154 | if (colorVariables) { 155 | source = setColorVariables(source, forceRGB) 156 | } 157 | if (!varPrefix) { 158 | varPrefix = '' 159 | } 160 | let componentOptions = {} 161 | _forEach(toPairs(flattenOptions(source)), ([key, config]) => { 162 | let block = key === 'DEFAULT' ? cssBaseKey : `${key}` 163 | 164 | if (!hasOwn(componentOptions, block)) { 165 | componentOptions[block] = [] 166 | } 167 | 168 | assign(componentOptions[block], parseVariables(config, varPrefix)) 169 | }) 170 | 171 | return componentOptions 172 | } 173 | 174 | const darkBuild = (options, darkMode, source) => { 175 | let varPrefix = formatVariableKey(get(options, 'variablePrefix', '')) 176 | if (!varPrefix) { 177 | varPrefix = '' 178 | } 179 | let colorVariables = get(options, 'colorVariables', false) 180 | let forceRGB = get(options, 'forceRGB', false) 181 | if (colorVariables) { 182 | source = setColorVariables(source, forceRGB) 183 | } 184 | let darkSelector = get(options, 'darkSelector') 185 | let darkToRoot = hasOwn(options, 'darkToRoot') ? options.darkToRoot : true 186 | let cssBaseKey = get(options, 'useHost', false) ? `:host` : `:root` 187 | 188 | let componentOptions = {} 189 | 190 | _forEach(toPairs(flattenOptions(source)), ([key, config]) => { 191 | let block 192 | 193 | if (key === 'DEFAULT') { 194 | if (darkMode === 'class') { 195 | block = darkToRoot ? `${cssBaseKey}${darkSelector}` : `${darkSelector}` 196 | } else { 197 | block = `${cssBaseKey}` 198 | } 199 | } else { 200 | if (darkMode === 'class') { 201 | block = darkToRoot ? `${cssBaseKey}${darkSelector} ${key}` : `${darkSelector} ${key}` 202 | } else { 203 | block = `${key}` 204 | } 205 | } 206 | 207 | if (!hasOwn(componentOptions, block)) { 208 | componentOptions[block] = [] 209 | } 210 | 211 | assign(componentOptions[block], parseVariables(config, varPrefix)) 212 | }) 213 | 214 | return componentOptions 215 | } 216 | 217 | module.exports.build = build 218 | module.exports.darkBuild = darkBuild 219 | module.exports.flattenOptions = flattenOptions 220 | module.exports.setComponent = setComponent 221 | module.exports.setVariable = setVariable 222 | module.exports.setDarkMediaVariable = setDarkMediaVariable 223 | --------------------------------------------------------------------------------
18 | [colorVariable() example]
18 | [dark mode with "darkSelector" option]
18 | [dark mode with "class" mode and darkToRoot option]
19 | [dark mode with "class"]
18 | [dark mode with "media"]
18 | [variablePrefix example]
18 | [simple example]
17 | [simple example]