Skip to content

Commit 5701d78

Browse files
authored
Add dark mode variant (#2279)
* Initial dark mode prototype * Isolate dark mode logic to config extension * Update fixtures * Fix lint warnings
1 parent 455b561 commit 5701d78

File tree

6 files changed

+135460
-76067
lines changed

6 files changed

+135460
-76067
lines changed

__tests__/darkMode.test.js

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import postcss from 'postcss'
2+
import tailwind from '../src/index'
3+
4+
function run(input, config = {}) {
5+
return postcss([tailwind({ experimental: { darkModeVariant: true }, ...config })]).process(
6+
input,
7+
{ from: undefined }
8+
)
9+
}
10+
11+
test('dark mode variants cannot be generated without enabling the dark mode experiment', () => {
12+
const input = `
13+
@variants dark {
14+
.text-red {
15+
color: red;
16+
}
17+
}
18+
`
19+
20+
expect.assertions(1)
21+
return expect(run(input, { experimental: {} })).rejects.toThrow()
22+
})
23+
24+
test('generating dark mode variants uses the media strategy by default', () => {
25+
const input = `
26+
@variants dark {
27+
.text-red {
28+
color: red;
29+
}
30+
}
31+
`
32+
33+
const expected = `
34+
.text-red {
35+
color: red;
36+
}
37+
@media (prefers-color-scheme: dark) {
38+
.dark\\:text-red {
39+
color: red;
40+
}
41+
}
42+
`
43+
44+
expect.assertions(2)
45+
46+
return run(input).then(result => {
47+
expect(result.css).toMatchCss(expected)
48+
expect(result.warnings().length).toBe(0)
49+
})
50+
})
51+
52+
test('dark mode variants can be generated using the class strategy', () => {
53+
const input = `
54+
@variants dark {
55+
.text-red {
56+
color: red;
57+
}
58+
}
59+
`
60+
61+
const expected = `
62+
.text-red {
63+
color: red;
64+
}
65+
.dark .dark\\:text-red {
66+
color: red;
67+
}
68+
`
69+
70+
expect.assertions(2)
71+
72+
return run(input, { dark: 'class' }).then(result => {
73+
expect(result.css).toMatchCss(expected)
74+
expect(result.warnings().length).toBe(0)
75+
})
76+
})
77+
78+
test('dark mode variants stack with other variants', () => {
79+
const input = `
80+
@variants responsive, dark, hover, focus {
81+
.text-red {
82+
color: red;
83+
}
84+
}
85+
`
86+
87+
const expected = `
88+
.text-red {
89+
color: red;
90+
}
91+
.hover\\:text-red:hover {
92+
color: red;
93+
}
94+
.focus\\:text-red:focus {
95+
color: red;
96+
}
97+
@media (prefers-color-scheme: dark) {
98+
.dark\\:text-red {
99+
color: red;
100+
}
101+
.dark\\:hover\\:text-red:hover {
102+
color: red;
103+
}
104+
.dark\\:focus\\:text-red:focus {
105+
color: red;
106+
}
107+
}
108+
@media (min-width: 500px) {
109+
.sm\\:text-red {
110+
color: red;
111+
}
112+
.sm\\:hover\\:text-red:hover {
113+
color: red;
114+
}
115+
.sm\\:focus\\:text-red:focus {
116+
color: red;
117+
}
118+
@media (prefers-color-scheme: dark) {
119+
.sm\\:dark\\:text-red {
120+
color: red;
121+
}
122+
.sm\\:dark\\:hover\\:text-red:hover {
123+
color: red;
124+
}
125+
.sm\\:dark\\:focus\\:text-red:focus {
126+
color: red;
127+
}
128+
}
129+
}
130+
@media (min-width: 800px) {
131+
.lg\\:text-red {
132+
color: red;
133+
}
134+
.lg\\:hover\\:text-red:hover {
135+
color: red;
136+
}
137+
.lg\\:focus\\:text-red:focus {
138+
color: red;
139+
}
140+
@media (prefers-color-scheme: dark) {
141+
.lg\\:dark\\:text-red {
142+
color: red;
143+
}
144+
.lg\\:dark\\:hover\\:text-red:hover {
145+
color: red;
146+
}
147+
.lg\\:dark\\:focus\\:text-red:focus {
148+
color: red;
149+
}
150+
}
151+
}
152+
`
153+
154+
expect.assertions(2)
155+
156+
return run(input, { theme: { screens: { sm: '500px', lg: '800px' } } }).then(result => {
157+
expect(result.css).toMatchCss(expected)
158+
expect(result.warnings().length).toBe(0)
159+
})
160+
})
161+
162+
test('dark mode variants stack with other variants when using the class strategy', () => {
163+
const input = `
164+
@variants responsive, dark, hover, focus {
165+
.text-red {
166+
color: red;
167+
}
168+
}
169+
`
170+
171+
const expected = `
172+
.text-red {
173+
color: red;
174+
}
175+
.hover\\:text-red:hover {
176+
color: red;
177+
}
178+
.focus\\:text-red:focus {
179+
color: red;
180+
}
181+
.dark .dark\\:text-red {
182+
color: red;
183+
}
184+
.dark .dark\\:hover\\:text-red:hover {
185+
color: red;
186+
}
187+
.dark .dark\\:focus\\:text-red:focus {
188+
color: red;
189+
}
190+
@media (min-width: 500px) {
191+
.sm\\:text-red {
192+
color: red;
193+
}
194+
.sm\\:hover\\:text-red:hover {
195+
color: red;
196+
}
197+
.sm\\:focus\\:text-red:focus {
198+
color: red;
199+
}
200+
.dark .sm\\:dark\\:text-red {
201+
color: red;
202+
}
203+
.dark .sm\\:dark\\:hover\\:text-red:hover {
204+
color: red;
205+
}
206+
.dark .sm\\:dark\\:focus\\:text-red:focus {
207+
color: red;
208+
}
209+
}
210+
@media (min-width: 800px) {
211+
.lg\\:text-red {
212+
color: red;
213+
}
214+
.lg\\:hover\\:text-red:hover {
215+
color: red;
216+
}
217+
.lg\\:focus\\:text-red:focus {
218+
color: red;
219+
}
220+
.dark .lg\\:dark\\:text-red {
221+
color: red;
222+
}
223+
.dark .lg\\:dark\\:hover\\:text-red:hover {
224+
color: red;
225+
}
226+
.dark .lg\\:dark\\:focus\\:text-red:focus {
227+
color: red;
228+
}
229+
}
230+
`
231+
232+
expect.assertions(2)
233+
234+
return run(input, { dark: 'class', theme: { screens: { sm: '500px', lg: '800px' } } }).then(
235+
result => {
236+
expect(result.css).toMatchCss(expected)
237+
expect(result.warnings().length).toBe(0)
238+
}
239+
)
240+
})

0 commit comments

Comments
 (0)