Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Commit f481cde

Browse files
authored
Add !font-bold-style important modifier (#174)
* Add basic experimental support for `!font-bold`-style important modifiers * Test important modifier when using prefix * Simplify changes
1 parent 260d9f4 commit f481cde

7 files changed

+212
-0
lines changed

src/lib/generateRules.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const parseObjectStyles = require('tailwindcss/lib/util/parseObjectStyles').defa
33
const { isPlainObject, bigSign } = require('./utils')
44
const selectorParser = require('postcss-selector-parser')
55
const prefixSelector = require('tailwindcss/lib/util/prefixSelector').default
6+
const { updateAllClasses } = require('../pluginUtils')
67

78
let classNameParser = selectorParser((selectors) => {
89
return selectors.first.filter(({ type }) => type === 'class').pop().value
@@ -64,6 +65,26 @@ function applyPrefix(matches, context) {
6465
return matches
6566
}
6667

68+
function applyImportant(matches) {
69+
if (matches.length === 0) {
70+
return matches
71+
}
72+
let result = []
73+
74+
for (let [meta, rule] of matches) {
75+
let container = postcss.root({ nodes: [rule] })
76+
container.walkRules((r) => {
77+
r.selector = updateAllClasses(r.selector, (className) => {
78+
return `!${className}`
79+
})
80+
r.walkDecls((d) => (d.important = true))
81+
})
82+
result.push([meta, container.nodes[0]])
83+
}
84+
85+
return result
86+
}
87+
6788
// Takes a list of rule tuples and applies a variant like `hover`, sm`,
6889
// whatever to it. We used to do some extra caching here to avoid generating
6990
// a variant of the same rule more than once, but this was never hit because
@@ -179,6 +200,12 @@ function sortAgainst(toSort, against) {
179200
function* resolveMatches(candidate, context) {
180201
let separator = context.tailwindConfig.separator
181202
let [classCandidate, ...variants] = candidate.split(separator).reverse()
203+
let important = false
204+
205+
if (classCandidate.startsWith('!')) {
206+
important = true
207+
classCandidate = classCandidate.slice(1)
208+
}
182209

183210
// Strip prefix
184211
// md:hover:tw-bg-black
@@ -220,6 +247,10 @@ function* resolveMatches(candidate, context) {
220247

221248
matches = applyPrefix(matches, context)
222249

250+
if (important) {
251+
matches = applyImportant(matches, context)
252+
}
253+
223254
for (let variant of variants) {
224255
matches = applyVariant(variant, matches, context)
225256
}

tests/14-important-modifier.test.css

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
* {
2+
--tw-shadow: 0 0 #0000;
3+
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
4+
--tw-ring-offset-width: 0px;
5+
--tw-ring-offset-color: #fff;
6+
--tw-ring-color: rgba(59, 130, 246, 0.5);
7+
--tw-ring-offset-shadow: 0 0 #0000;
8+
--tw-ring-shadow: 0 0 #0000;
9+
}
10+
.\!container {
11+
width: 100% !important;
12+
}
13+
@media (min-width: 640px) {
14+
.\!container {
15+
max-width: 640px !important;
16+
}
17+
}
18+
@media (min-width: 768px) {
19+
.\!container {
20+
max-width: 768px !important;
21+
}
22+
}
23+
@media (min-width: 1024px) {
24+
.\!container {
25+
max-width: 1024px !important;
26+
}
27+
}
28+
@media (min-width: 1280px) {
29+
.\!container {
30+
max-width: 1280px !important;
31+
}
32+
}
33+
@media (min-width: 1536px) {
34+
.\!container {
35+
max-width: 1536px !important;
36+
}
37+
}
38+
.\!font-bold {
39+
font-weight: 700 !important;
40+
}
41+
.hover\:\!text-center:hover {
42+
text-align: center !important;
43+
}
44+
@media (min-width: 1024px) {
45+
.lg\:\!opacity-50 {
46+
opacity: 0.5 !important;
47+
}
48+
}
49+
@media (min-width: 1280px) {
50+
.xl\:focus\:disabled\:\!float-right:focus:disabled {
51+
float: right !important;
52+
}
53+
}

tests/14-important-modifier.test.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="!container"></div>
2+
<div class="!font-bold"></div>
3+
<div class="hover:!text-center"></div>
4+
<div class="lg:!opacity-50"></div>
5+
<div class="xl:focus:disabled:!float-right"></div>

tests/14-important-modifier.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const postcss = require('postcss')
2+
const tailwind = require('../src/index.js')
3+
const fs = require('fs')
4+
const path = require('path')
5+
6+
function run(input, config = {}) {
7+
return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) })
8+
}
9+
10+
test('important modifier', () => {
11+
let config = {
12+
important: false,
13+
darkMode: 'class',
14+
purge: [path.resolve(__dirname, './14-important-modifier.test.html')],
15+
corePlugins: { preflight: false },
16+
theme: {},
17+
plugins: [],
18+
}
19+
20+
let css = `
21+
@tailwind base;
22+
@tailwind components;
23+
@tailwind utilities;
24+
`
25+
26+
return run(css, config).then((result) => {
27+
let expectedPath = path.resolve(__dirname, './14-important-modifier.test.css')
28+
let expected = fs.readFileSync(expectedPath, 'utf8')
29+
30+
expect(result.css).toMatchCss(expected)
31+
})
32+
})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
* {
2+
--tw-shadow: 0 0 #0000;
3+
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
4+
--tw-ring-offset-width: 0px;
5+
--tw-ring-offset-color: #fff;
6+
--tw-ring-color: rgba(59, 130, 246, 0.5);
7+
--tw-ring-offset-shadow: 0 0 #0000;
8+
--tw-ring-shadow: 0 0 #0000;
9+
}
10+
.\!tw-container {
11+
width: 100% !important;
12+
}
13+
@media (min-width: 640px) {
14+
.\!tw-container {
15+
max-width: 640px !important;
16+
}
17+
}
18+
@media (min-width: 768px) {
19+
.\!tw-container {
20+
max-width: 768px !important;
21+
}
22+
}
23+
@media (min-width: 1024px) {
24+
.\!tw-container {
25+
max-width: 1024px !important;
26+
}
27+
}
28+
@media (min-width: 1280px) {
29+
.\!tw-container {
30+
max-width: 1280px !important;
31+
}
32+
}
33+
@media (min-width: 1536px) {
34+
.\!tw-container {
35+
max-width: 1536px !important;
36+
}
37+
}
38+
.\!tw-font-bold {
39+
font-weight: 700 !important;
40+
}
41+
.hover\:\!tw-text-center:hover {
42+
text-align: center !important;
43+
}
44+
@media (min-width: 1024px) {
45+
.lg\:\!tw-opacity-50 {
46+
opacity: 0.5 !important;
47+
}
48+
}
49+
@media (min-width: 1280px) {
50+
.xl\:focus\:disabled\:\!tw-float-right:focus:disabled {
51+
float: right !important;
52+
}
53+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="!tw-container"></div>
2+
<div class="!tw-font-bold"></div>
3+
<div class="hover:!tw-text-center"></div>
4+
<div class="lg:!tw-opacity-50"></div>
5+
<div class="xl:focus:disabled:!tw-float-right"></div>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const postcss = require('postcss')
2+
const tailwind = require('../src/index.js')
3+
const fs = require('fs')
4+
const path = require('path')
5+
6+
function run(input, config = {}) {
7+
return postcss([tailwind(config)]).process(input, { from: path.resolve(__filename) })
8+
}
9+
10+
test('important modifier with prefix', () => {
11+
let config = {
12+
important: false,
13+
prefix: 'tw-',
14+
darkMode: 'class',
15+
purge: [path.resolve(__dirname, './15-important-modifier-prefix.test.html')],
16+
corePlugins: { preflight: false },
17+
theme: {},
18+
plugins: [],
19+
}
20+
21+
let css = `
22+
@tailwind base;
23+
@tailwind components;
24+
@tailwind utilities;
25+
`
26+
27+
return run(css, config).then((result) => {
28+
let expectedPath = path.resolve(__dirname, './15-important-modifier-prefix.test.css')
29+
let expected = fs.readFileSync(expectedPath, 'utf8')
30+
31+
expect(result.css).toMatchCss(expected)
32+
})
33+
})

0 commit comments

Comments
 (0)