Skip to content

Commit a05b369

Browse files
adamwathanNick Schmidtneupauer
committed
Add CSS filter support (#3923)
* Implement `filter` helper classes with all methods * Rename filter plugins/utilities, drop filter opacity, add drop shadow * Remove non-final default filter values * Working on default filter values, add basic JIT support * Working on blur values * New blur values (these are ~okay) * Match drop-shadow values to box-shadows by eye as best as possible * Update tests * Fix kitchen sink test * Add filter variants configuration * Move drop-shadow to end of filters list Co-Authored-By: Peter Neupauer <[email protected]> * Add invert variants configuration * Add backdrop-filter utilities * Update tests * Transition filters by default * Alphabetize new config keys * Optimize filter plugins for JIT + add arbitrary value support Except for drop-shadow, will add that once we can think it through a bit. Co-authored-by: Nick Schmidt <[email protected]> Co-authored-by: Peter Neupauer <[email protected]>
1 parent 359ce6b commit a05b369

36 files changed

+11398
-38
lines changed

__tests__/fixtures/tailwind-output-flagged.css

+2,582-6
Large diffs are not rendered by default.

__tests__/fixtures/tailwind-output-important.css

+2,582-6
Large diffs are not rendered by default.

__tests__/fixtures/tailwind-output-no-color-opacity.css

+2,582-6
Large diffs are not rendered by default.

__tests__/fixtures/tailwind-output.css

+2,582-6
Large diffs are not rendered by default.

jit/corePlugins/index.js

+22
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,28 @@ module.exports = {
292292
ringOffsetWidth: require('./ringOffsetWidth'),
293293
ringOffsetColor: require('./ringOffsetColor'),
294294

295+
filter: require('../../lib/plugins/filter').default(),
296+
blur: require('../../lib/plugins/blur').default(),
297+
brightness: require('../../lib/plugins/brightness').default(),
298+
contrast: require('../../lib/plugins/contrast').default(),
299+
dropShadow: require('../../lib/plugins/dropShadow').default(),
300+
grayscale: require('../../lib/plugins/grayscale').default(),
301+
hueRotate: require('../../lib/plugins/hueRotate').default(),
302+
invert: require('../../lib/plugins/invert').default(),
303+
saturate: require('../../lib/plugins/saturate').default(),
304+
sepia: require('../../lib/plugins/sepia').default(),
305+
306+
backdropFilter: require('../../lib/plugins/backdropFilter').default(),
307+
backdropBlur: require('../../lib/plugins/backdropBlur').default(),
308+
backdropBrightness: require('../../lib/plugins/backdropBrightness').default(),
309+
backdropContrast: require('../../lib/plugins/backdropContrast').default(),
310+
backdropGrayscale: require('../../lib/plugins/backdropGrayscale').default(),
311+
backdropHueRotate: require('../../lib/plugins/backdropHueRotate').default(),
312+
backdropInvert: require('../../lib/plugins/backdropInvert').default(),
313+
backdropOpacity: require('../../lib/plugins/backdropOpacity').default(),
314+
backdropSaturate: require('../../lib/plugins/backdropSaturate').default(),
315+
backdropSepia: require('../../lib/plugins/backdropSepia').default(),
316+
295317
transitionProperty: require('./transitionProperty'),
296318
transitionDelay: require('./transitionDelay'),
297319
transitionDuration: require('./transitionDuration'),

jit/tests/arbitrary-values.test.css

+51
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,57 @@
136136
.text-\[2\.23rem\] {
137137
font-size: 2.23rem;
138138
}
139+
.blur-\[15px\] {
140+
--tw-blur: blur(15px);
141+
}
142+
.brightness-\[300\%\] {
143+
--tw-brightness: brightness(300%);
144+
}
145+
.contrast-\[2\.4\] {
146+
--tw-contrast: contrast(2.4);
147+
}
148+
.grayscale-\[0\.55\] {
149+
--tw-grayscale: grayscale(0.55);
150+
}
151+
.hue-rotate-\[0\.8turn\] {
152+
--tw-hue-rotate: hue-rotate(0.8turn);
153+
}
154+
.invert-\[0\.75\] {
155+
--tw-invert: invert(0.75);
156+
}
157+
.saturate-\[180\%\] {
158+
--tw-saturate: saturate(180%);
159+
}
160+
.sepia-\[0\.2\] {
161+
--tw-sepia: sepia(0.2);
162+
}
163+
.backdrop-blur-\[11px\] {
164+
--tw-backdrop-blur: blur(11px);
165+
}
166+
.backdrop-brightness-\[1\.23\] {
167+
--tw-backdrop-brightness: brightness(1.23);
168+
}
169+
.backdrop-contrast-\[0\.87\] {
170+
--tw-backdrop-contrast: contrast(0.87);
171+
}
172+
.backdrop-grayscale-\[0\.42\] {
173+
--tw-backdrop-grayscale: grayscale(0.42);
174+
}
175+
.backdrop-hue-rotate-\[1\.57rad\] {
176+
--tw-backdrop-hue-rotate: hue-rotate(1.57rad);
177+
}
178+
.backdrop-invert-\[0\.66\] {
179+
--tw-backdrop-invert: invert(0.66);
180+
}
181+
.backdrop-opacity-\[22\%\] {
182+
--tw-backdrop-opacity: opacity(22%);
183+
}
184+
.backdrop-saturate-\[144\%\] {
185+
--tw-backdrop-saturate: saturate(144%);
186+
}
187+
.backdrop-sepia-\[0\.38\] {
188+
--tw-backdrop-sepia: sepia(0.38);
189+
}
139190
.duration-\[2s\] {
140191
transition-duration: 2s;
141192
}

jit/tests/arbitrary-values.test.html

+17
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,22 @@
4343
<div class="duration-[var(--app-duration)]"></div>
4444
<div class="p-[var(--app-padding)]"></div>
4545
<div class="inset-[11px]"></div>
46+
<div class="blur-[15px]"></div>
47+
<div class="brightness-[300%]"></div>
48+
<div class="contrast-[2.4]"></div>
49+
<div class="grayscale-[0.55]"></div>
50+
<div class="hue-rotate-[0.8turn]"></div>
51+
<div class="invert-[0.75]"></div>
52+
<div class="saturate-[180%]"></div>
53+
<div class="sepia-[0.2]"></div>
54+
<div class="backdrop-blur-[11px]"></div>
55+
<div class="backdrop-brightness-[1.23]"></div>
56+
<div class="backdrop-contrast-[0.87]"></div>
57+
<div class="backdrop-grayscale-[0.42]"></div>
58+
<div class="backdrop-hue-rotate-[1.57rad]"></div>
59+
<div class="backdrop-invert-[0.66]"></div>
60+
<div class="backdrop-opacity-[22%]"></div>
61+
<div class="backdrop-saturate-[144%]"></div>
62+
<div class="backdrop-sepia-[0.38]"></div>
4663
</body>
4764
</html>

jit/tests/arbitrary-values.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function run(input, config = {}) {
99

1010
test('arbitrary values', () => {
1111
let config = {
12+
mode: 'jit',
1213
purge: [path.resolve(__dirname, './arbitrary-values.test.html')],
1314
corePlugins: { preflight: false },
1415
theme: {},

jit/tests/basic-usage.test.css

+89-1
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,97 @@
633633
.ring-offset-blue-300 {
634634
--tw-ring-offset-color: #93c5fd;
635635
}
636+
.filter {
637+
--tw-blur: var(--tw-empty, /*!*/ /*!*/);
638+
--tw-brightness: var(--tw-empty, /*!*/ /*!*/);
639+
--tw-contrast: var(--tw-empty, /*!*/ /*!*/);
640+
--tw-grayscale: var(--tw-empty, /*!*/ /*!*/);
641+
--tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/);
642+
--tw-invert: var(--tw-empty, /*!*/ /*!*/);
643+
--tw-saturate: var(--tw-empty, /*!*/ /*!*/);
644+
--tw-sepia: var(--tw-empty, /*!*/ /*!*/);
645+
--tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/);
646+
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale)
647+
var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
648+
}
649+
.filter-none {
650+
filter: none;
651+
}
652+
.blur-md {
653+
--tw-blur: blur(12px);
654+
}
655+
.brightness-150 {
656+
--tw-brightness: brightness(1.5);
657+
}
658+
.contrast-50 {
659+
--tw-contrast: contrast(0.5);
660+
}
661+
.drop-shadow-md {
662+
--tw-drop-shadow: drop-shadow(0 4px 3px rgba(0, 0, 0, 0.07))
663+
drop-shadow(0 2px 2px rgba(0, 0, 0, 0.06));
664+
}
665+
.grayscale {
666+
--tw-grayscale: grayscale(100%);
667+
}
668+
.hue-rotate-60 {
669+
--tw-hue-rotate: hue-rotate(60deg);
670+
}
671+
.invert {
672+
--tw-invert: invert(100%);
673+
}
674+
.saturate-200 {
675+
--tw-saturate: saturate(2);
676+
}
677+
.sepia {
678+
--tw-sepia: sepia(100%);
679+
}
680+
.backdrop-filter {
681+
--tw-backdrop-blur: var(--tw-empty, /*!*/ /*!*/);
682+
--tw-backdrop-brightness: var(--tw-empty, /*!*/ /*!*/);
683+
--tw-backdrop-contrast: var(--tw-empty, /*!*/ /*!*/);
684+
--tw-backdrop-grayscale: var(--tw-empty, /*!*/ /*!*/);
685+
--tw-backdrop-hue-rotate: var(--tw-empty, /*!*/ /*!*/);
686+
--tw-backdrop-invert: var(--tw-empty, /*!*/ /*!*/);
687+
--tw-backdrop-opacity: var(--tw-empty, /*!*/ /*!*/);
688+
--tw-backdrop-saturate: var(--tw-empty, /*!*/ /*!*/);
689+
--tw-backdrop-sepia: var(--tw-empty, /*!*/ /*!*/);
690+
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast)
691+
var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
692+
var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
693+
}
694+
.backdrop-filter-none {
695+
backdrop-filter: none;
696+
}
697+
.backdrop-blur-lg {
698+
--tw-backdrop-blur: blur(16px);
699+
}
700+
.backdrop-brightness-50 {
701+
--tw-backdrop-brightness: brightness(0.5);
702+
}
703+
.backdrop-contrast-0 {
704+
--tw-backdrop-contrast: contrast(0);
705+
}
706+
.backdrop-grayscale {
707+
--tw-backdrop-grayscale: grayscale(100%);
708+
}
709+
.backdrop-hue-rotate-90 {
710+
--tw-backdrop-hue-rotate: hue-rotate(90deg);
711+
}
712+
.backdrop-invert {
713+
--tw-backdrop-invert: invert(100%);
714+
}
715+
.backdrop-opacity-75 {
716+
--tw-backdrop-opacity: opacity(0.75);
717+
}
718+
.backdrop-saturate-150 {
719+
--tw-backdrop-saturate: saturate(1.5);
720+
}
721+
.backdrop-sepia {
722+
--tw-backdrop-sepia: sepia(100%);
723+
}
636724
.transition {
637725
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow,
638-
transform;
726+
transform, filter, backdrop-filter;
639727
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
640728
transition-duration: 150ms;
641729
}

jit/tests/basic-usage.test.html

+6
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@
108108
<div class="ring-offset-2"></div>
109109
<div class="ring-opacity-40"></div>
110110
<div class="ring ring-4"></div>
111+
<div
112+
class="filter filter-none blur-md brightness-150 contrast-50 drop-shadow-md grayscale hue-rotate-60 invert saturate-200 sepia"
113+
></div>
114+
<div
115+
class="backdrop-filter backdrop-filter-none backdrop-blur-lg backdrop-brightness-50 backdrop-contrast-0 backdrop-grayscale backdrop-hue-rotate-90 backdrop-invert backdrop-opacity-75 backdrop-saturate-150 backdrop-sepia"
116+
></div>
111117
<div class="rotate-3"></div>
112118
<div class="scale-95"></div>
113119
<div class="skew-y-12 skew-x-12"></div>

jit/tests/kitchen-sink.test.css

+7-7
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,11 @@ div {
314314
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
315315
var(--tw-shadow);
316316
}
317-
.filter-none {
318-
filter: none;
317+
.magic-none {
318+
magic: none;
319319
}
320-
.filter-grayscale {
321-
filter: grayscale(100%);
320+
.magic-tons {
321+
magic: tons;
322322
}
323323
.custom-util {
324324
background: #abcdef;
@@ -410,7 +410,7 @@ div {
410410
@media (prefers-reduced-motion: no-preference) {
411411
.motion-safe\:transition {
412412
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow,
413-
transform;
413+
transform, filter, backdrop-filter;
414414
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
415415
transition-duration: 150ms;
416416
}
@@ -421,7 +421,7 @@ div {
421421
@media (prefers-reduced-motion: reduce) {
422422
.motion-reduce\:transition {
423423
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow,
424-
transform;
424+
transform, filter, backdrop-filter;
425425
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
426426
transition-duration: 150ms;
427427
}
@@ -535,7 +535,7 @@ div {
535535
@media (prefers-reduced-motion: no-preference) {
536536
.md\:motion-safe\:hover\:transition:hover {
537537
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow,
538-
transform;
538+
transform, filter, backdrop-filter;
539539
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
540540
transition-duration: 150ms;
541541
}

jit/tests/kitchen-sink.test.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<div class="md:dark:motion-safe:foo:active:custom-util"></div>
2828
<div class="aspect-w-1 aspect-h-2"></div>
2929
<div class="aspect-w-3 aspect-h-4"></div>
30-
<div class="filter-none filter-grayscale"></div>
30+
<div class="magic-none magic-tons"></div>
3131
<div class="focus:font-normal"></div>
3232
<div class="font-medium"></div>
3333
<div class="bg-gradient-to-r from-foo"></div>

jit/tests/kitchen-sink.test.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ test('it works', () => {
5555
})
5656
addUtilities(
5757
{
58-
'.filter-none': {
59-
filter: 'none',
58+
'.magic-none': {
59+
magic: 'none',
6060
},
61-
'.filter-grayscale': {
62-
filter: 'grayscale(100%)',
61+
'.magic-tons': {
62+
magic: 'tons',
6363
},
6464
},
6565
['responsive', 'hover']

src/corePluginList.js

+20
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,24 @@ export const corePluginList = [
122122
'animation',
123123
'mixBlendMode',
124124
'backgroundBlendMode',
125+
'filter',
126+
'blur',
127+
'brightness',
128+
'contrast',
129+
'dropShadow',
130+
'grayscale',
131+
'hueRotate',
132+
'invert',
133+
'saturate',
134+
'sepia',
135+
'backdropFilter',
136+
'backdropBlur',
137+
'backdropBrightness',
138+
'backdropContrast',
139+
'backdropGrayscale',
140+
'backdropHueRotate',
141+
'backdropInvert',
142+
'backdropOpacity',
143+
'backdropSaturate',
144+
'backdropSepia',
125145
]

src/plugins/backdropBlur.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import _ from 'lodash'
2+
const { asValue, nameClass } = require('../../jit/pluginUtils')
3+
4+
export default function () {
5+
return function ({ config, matchUtilities, addUtilities, theme, variants }) {
6+
if (config('mode') === 'jit') {
7+
matchUtilities({
8+
'backdrop-blur': (modifier, { theme }) => {
9+
let value = asValue(modifier, theme.backdropBlur)
10+
11+
if (value === undefined) {
12+
return []
13+
}
14+
15+
return {
16+
[nameClass('backdrop-blur', modifier)]: { '--tw-backdrop-blur': `blur(${value})` },
17+
}
18+
},
19+
})
20+
} else {
21+
const utilities = _.fromPairs(
22+
_.map(theme('backdropBlur'), (value, modifier) => {
23+
return [
24+
nameClass('backdrop-blur', modifier),
25+
{
26+
'--tw-backdrop-blur': Array.isArray(value)
27+
? value.map((v) => `blur(${v})`).join(' ')
28+
: `blur(${value})`,
29+
},
30+
]
31+
})
32+
)
33+
34+
addUtilities(utilities, variants('backdopBlur'))
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)