Skip to content

Commit 71d3922

Browse files
committed
Add support for TailwindCSS v3
1 parent c2613c1 commit 71d3922

File tree

6 files changed

+2432
-3536
lines changed

6 files changed

+2432
-3536
lines changed

index.js

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,36 @@
1-
const tailwindConfig = require('./tailwind.config.js')
2-
const { buildPlugin } = require('@hacknug/tailwindcss-plugin-utils')
1+
const flat = require('flat')
2+
const plugin = require('tailwindcss/plugin')
33

4-
module.exports = function (pluginConfig) {
5-
return function (coreUtils) {
6-
return buildPlugin(coreUtils, tailwindConfig, [
7-
{ key: ['textFillColor', 'borderColor'], base: 'text-fill', property: '-webkit-text-fill-color' },
8-
{ key: ['textStrokeColor', 'borderColor'], base: 'text-stroke', property: '-webkit-text-stroke-color' },
9-
{ key: ['textStrokeWidth', 'borderWidth'], base: 'text-stroke', property: '-webkit-text-stroke-width' },
10-
{ key: ['paintOrder'], base: 'paint' },
11-
])
12-
}
13-
}
4+
const normalizeValues = (config) => Object.fromEntries(
5+
Object.entries(flat(config, { delimiter: '-', maxDepth: 2 })).sort(([a], [b]) => a === 'DEFAULT' ? -1 : 1)
6+
)
7+
8+
module.exports = plugin(({ matchUtilities, theme }) => {
9+
matchUtilities(
10+
{ 'text-fill': (value) => ({ '-webkit-text-fill-color': value }) },
11+
{ values: normalizeValues(theme('textFillColor', theme('borderColor'))), type: ['color'] },
12+
)
13+
matchUtilities(
14+
{ 'text-stroke': (value) => ({ '-webkit-text-stroke-color': value }) },
15+
{ values: normalizeValues(theme('textStrokeColor', theme('borderColor'))), type: ['color'] },
16+
)
17+
matchUtilities(
18+
{ 'text-stroke': (value) => ({ '-webkit-text-stroke-width': value }) },
19+
{ values: normalizeValues(theme('textStrokeWidth', theme('borderWidth'))), type: ['length'] },
20+
)
21+
matchUtilities(
22+
{ 'paint': (value) => ({ paintOrder: value }) },
23+
{ values: normalizeValues(theme('paintOrder')) },
24+
)
25+
}, {
26+
theme: {
27+
paintOrder: {
28+
'fsm': 'fill stroke markers',
29+
'fms': 'fill markers stroke',
30+
'sfm': 'stroke fill markers',
31+
'smf': 'stroke markers fill',
32+
'mfs': 'markers fill stroke',
33+
'msf': 'markers stroke fill',
34+
},
35+
},
36+
})

index.test.js

Lines changed: 86 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const tailwindConfig = require('./tailwind.config.js')
2-
const { generatePluginCss } = require('@hacknug/tailwindcss-plugin-utils')
1+
const postcss = require('postcss')
2+
const tailwind = require('tailwindcss')
33

44
expect.extend({ toMatchCss: require('jest-matcher-css') })
55

@@ -8,8 +8,10 @@ const pluginOptions = {}
88

99
const commonConfig = {
1010
theme: {
11-
screens: { 'sm': '640px' },
11+
screens: { sm: '640px' },
1212
colors: {
13+
// inherit: 'inherit',
14+
// current: 'currentColor',
1315
transparent: 'transparent',
1416
black: '#000',
1517
white: '#fff',
@@ -26,13 +28,17 @@ const commonConfig = {
2628
},
2729
},
2830
},
31+
plugins: [plugin],
2932
corePlugins: false,
30-
plugins: [plugin(pluginOptions)],
33+
safelist: [
34+
{ pattern: /.*/ },
35+
],
3136
}
3237

3338
test('generates default utilities', () => {
3439
const testConfig = { ...commonConfig }
3540
const expectedCss = `
41+
.text-fill { -webkit-text-fill-color: #eeeeee; }
3642
.text-fill-transparent { -webkit-text-fill-color: transparent }
3743
.text-fill-black { -webkit-text-fill-color: #000 }
3844
.text-fill-white { -webkit-text-fill-color: #fff }
@@ -45,8 +51,8 @@ test('generates default utilities', () => {
4551
.text-fill-gray-700 { -webkit-text-fill-color: #616161 }
4652
.text-fill-gray-800 { -webkit-text-fill-color: #424242 }
4753
.text-fill-gray-900 { -webkit-text-fill-color: #212121 }
48-
.text-fill { -webkit-text-fill-color: #e0e0e0 }
4954
55+
.text-stroke { -webkit-text-stroke-color: #eeeeee }
5056
.text-stroke-transparent { -webkit-text-stroke-color: transparent }
5157
.text-stroke-black { -webkit-text-stroke-color: #000 }
5258
.text-stroke-white { -webkit-text-stroke-color: #fff }
@@ -59,182 +65,126 @@ test('generates default utilities', () => {
5965
.text-stroke-gray-700 { -webkit-text-stroke-color: #616161 }
6066
.text-stroke-gray-800 { -webkit-text-stroke-color: #424242 }
6167
.text-stroke-gray-900 { -webkit-text-stroke-color: #212121 }
62-
.text-stroke { -webkit-text-stroke-color: #e0e0e0 }
6368
64-
.text-stroke-0 { -webkit-text-stroke-width: 0 }
65-
.text-stroke-2 { -webkit-text-stroke-width: 2px }
66-
.text-stroke-4 { -webkit-text-stroke-width: 4px }
67-
.text-stroke-8 { -webkit-text-stroke-width: 8px }
6869
.text-stroke { -webkit-text-stroke-width: 1px }
69-
70-
.paint-fsm { paint-order: fill stroke markers }
71-
.paint-fms { paint-order: fill markers stroke }
72-
.paint-sfm { paint-order: stroke fill markers }
73-
.paint-smf { paint-order: stroke markers fill }
74-
.paint-mfs { paint-order: markers fill stroke }
75-
.paint-msf { paint-order: markers stroke fill }
76-
`
77-
78-
return generatePluginCss(tailwindConfig, testConfig).then(css => expect(css).toMatchCss(expectedCss))
79-
})
80-
81-
test('variants can be customized', () => {
82-
const testConfig = {
83-
...commonConfig,
84-
variants: {
85-
textFillColor: ['hover'],
86-
textStrokeColor: ['focus'],
87-
textStrokeWidth: ['active'],
88-
paintOrder: ['responsive', 'hover'],
89-
},
90-
}
91-
const expectedCss = `
92-
.text-fill-transparent { -webkit-text-fill-color: transparent }
93-
.text-fill-black { -webkit-text-fill-color: #000 }
94-
.text-fill-white { -webkit-text-fill-color: #fff }
95-
.text-fill-gray-100 { -webkit-text-fill-color: #f5f5f5 }
96-
.text-fill-gray-200 { -webkit-text-fill-color: #eeeeee }
97-
.text-fill-gray-300 { -webkit-text-fill-color: #e0e0e0 }
98-
.text-fill-gray-400 { -webkit-text-fill-color: #bdbdbd }
99-
.text-fill-gray-500 { -webkit-text-fill-color: #9e9e9e }
100-
.text-fill-gray-600 { -webkit-text-fill-color: #757575 }
101-
.text-fill-gray-700 { -webkit-text-fill-color: #616161 }
102-
.text-fill-gray-800 { -webkit-text-fill-color: #424242 }
103-
.text-fill-gray-900 { -webkit-text-fill-color: #212121 }
104-
.text-fill { -webkit-text-fill-color: #e0e0e0 }
105-
106-
.hover\\:text-fill-transparent:hover { -webkit-text-fill-color: transparent }
107-
.hover\\:text-fill-black:hover { -webkit-text-fill-color: #000 }
108-
.hover\\:text-fill-white:hover { -webkit-text-fill-color: #fff }
109-
.hover\\:text-fill-gray-100:hover { -webkit-text-fill-color: #f5f5f5 }
110-
.hover\\:text-fill-gray-200:hover { -webkit-text-fill-color: #eeeeee }
111-
.hover\\:text-fill-gray-300:hover { -webkit-text-fill-color: #e0e0e0 }
112-
.hover\\:text-fill-gray-400:hover { -webkit-text-fill-color: #bdbdbd }
113-
.hover\\:text-fill-gray-500:hover { -webkit-text-fill-color: #9e9e9e }
114-
.hover\\:text-fill-gray-600:hover { -webkit-text-fill-color: #757575 }
115-
.hover\\:text-fill-gray-700:hover { -webkit-text-fill-color: #616161 }
116-
.hover\\:text-fill-gray-800:hover { -webkit-text-fill-color: #424242 }
117-
.hover\\:text-fill-gray-900:hover { -webkit-text-fill-color: #212121 }
118-
.hover\\:text-fill:hover { -webkit-text-fill-color: #e0e0e0 }
119-
120-
.text-stroke-transparent { -webkit-text-stroke-color: transparent }
121-
.text-stroke-black { -webkit-text-stroke-color: #000 }
122-
.text-stroke-white { -webkit-text-stroke-color: #fff }
123-
.text-stroke-gray-100 { -webkit-text-stroke-color: #f5f5f5 }
124-
.text-stroke-gray-200 { -webkit-text-stroke-color: #eeeeee }
125-
.text-stroke-gray-300 { -webkit-text-stroke-color: #e0e0e0 }
126-
.text-stroke-gray-400 { -webkit-text-stroke-color: #bdbdbd }
127-
.text-stroke-gray-500 { -webkit-text-stroke-color: #9e9e9e }
128-
.text-stroke-gray-600 { -webkit-text-stroke-color: #757575 }
129-
.text-stroke-gray-700 { -webkit-text-stroke-color: #616161 }
130-
.text-stroke-gray-800 { -webkit-text-stroke-color: #424242 }
131-
.text-stroke-gray-900 { -webkit-text-stroke-color: #212121 }
132-
.text-stroke { -webkit-text-stroke-color: #e0e0e0 }
133-
134-
.focus\\:text-stroke-transparent:focus { -webkit-text-stroke-color: transparent }
135-
.focus\\:text-stroke-black:focus { -webkit-text-stroke-color: #000 }
136-
.focus\\:text-stroke-white:focus { -webkit-text-stroke-color: #fff }
137-
.focus\\:text-stroke-gray-100:focus { -webkit-text-stroke-color: #f5f5f5 }
138-
.focus\\:text-stroke-gray-200:focus { -webkit-text-stroke-color: #eeeeee }
139-
.focus\\:text-stroke-gray-300:focus { -webkit-text-stroke-color: #e0e0e0 }
140-
.focus\\:text-stroke-gray-400:focus { -webkit-text-stroke-color: #bdbdbd }
141-
.focus\\:text-stroke-gray-500:focus { -webkit-text-stroke-color: #9e9e9e }
142-
.focus\\:text-stroke-gray-600:focus { -webkit-text-stroke-color: #757575 }
143-
.focus\\:text-stroke-gray-700:focus { -webkit-text-stroke-color: #616161 }
144-
.focus\\:text-stroke-gray-800:focus { -webkit-text-stroke-color: #424242 }
145-
.focus\\:text-stroke-gray-900:focus { -webkit-text-stroke-color: #212121 }
146-
.focus\\:text-stroke:focus { -webkit-text-stroke-color: #e0e0e0 }
147-
148-
.text-stroke-0 { -webkit-text-stroke-width: 0 }
70+
.text-stroke-0 { -webkit-text-stroke-width: 0px }
14971
.text-stroke-2 { -webkit-text-stroke-width: 2px }
15072
.text-stroke-4 { -webkit-text-stroke-width: 4px }
15173
.text-stroke-8 { -webkit-text-stroke-width: 8px }
152-
.text-stroke { -webkit-text-stroke-width: 1px }
153-
154-
.active\\:text-stroke-0:active { -webkit-text-stroke-width: 0 }
155-
.active\\:text-stroke-2:active { -webkit-text-stroke-width: 2px }
156-
.active\\:text-stroke-4:active { -webkit-text-stroke-width: 4px }
157-
.active\\:text-stroke-8:active { -webkit-text-stroke-width: 8px }
158-
.active\\:text-stroke:active { -webkit-text-stroke-width: 1px }
15974
16075
.paint-fsm { paint-order: fill stroke markers }
16176
.paint-fms { paint-order: fill markers stroke }
16277
.paint-sfm { paint-order: stroke fill markers }
16378
.paint-smf { paint-order: stroke markers fill }
16479
.paint-mfs { paint-order: markers fill stroke }
16580
.paint-msf { paint-order: markers stroke fill }
166-
167-
.hover\\:paint-fsm:hover { paint-order: fill stroke markers }
168-
.hover\\:paint-fms:hover { paint-order: fill markers stroke }
169-
.hover\\:paint-sfm:hover { paint-order: stroke fill markers }
170-
.hover\\:paint-smf:hover { paint-order: stroke markers fill }
171-
.hover\\:paint-mfs:hover { paint-order: markers fill stroke }
172-
.hover\\:paint-msf:hover { paint-order: markers stroke fill }
173-
174-
@media (min-width: 640px) {
175-
.sm\\:paint-fsm { paint-order: fill stroke markers }
176-
.sm\\:paint-fms { paint-order: fill markers stroke }
177-
.sm\\:paint-sfm { paint-order: stroke fill markers }
178-
.sm\\:paint-smf { paint-order: stroke markers fill }
179-
.sm\\:paint-mfs { paint-order: markers fill stroke }
180-
.sm\\:paint-msf { paint-order: markers stroke fill }
181-
182-
.sm\\:hover\\:paint-fsm:hover { paint-order: fill stroke markers }
183-
.sm\\:hover\\:paint-fms:hover { paint-order: fill markers stroke }
184-
.sm\\:hover\\:paint-sfm:hover { paint-order: stroke fill markers }
185-
.sm\\:hover\\:paint-smf:hover { paint-order: stroke markers fill }
186-
.sm\\:hover\\:paint-mfs:hover { paint-order: markers fill stroke }
187-
.sm\\:hover\\:paint-msf:hover { paint-order: markers stroke fill }
188-
}
18981
`
19082

191-
return generatePluginCss(tailwindConfig, testConfig).then(css => expect(css).toMatchCss(expectedCss))
83+
return postcss(tailwind(testConfig)).process('@tailwind utilities', { from: undefined })
84+
.then((result) => expect(result.css).toMatchCss(expectedCss))
19285
})
19386

19487
test('utilities can be customized', () => {
19588
const testConfig = {
19689
...commonConfig,
19790
theme: {
19891
textFillColor: theme => ({
92+
DEFAULT: '#38b2ac',
19993
transparent: 'transparent',
20094
black: '#000',
20195
white: '#fff',
20296
gray: '#9e9e9e',
203-
default: '#38b2ac',
20497
}),
20598
textStrokeColor: theme => ({
99+
DEFAULT: '#38b2ac',
206100
transparent: theme('colors.transparent'),
207-
default: '#38b2ac'
208101
}),
209-
textStrokeWidth: { default: '1px', sm: '2px', md: '4px', lg: '8px' },
102+
textStrokeWidth: { DEFAULT: '1px', sm: '2px', md: '4px', lg: '8px' },
210103
paintOrder: { stroke: 'stroke' }
211104
},
212105
}
213106
const expectedCss = `
107+
.text-fill { -webkit-text-fill-color: #38b2ac }
214108
.text-fill-transparent { -webkit-text-fill-color: transparent }
215109
.text-fill-black { -webkit-text-fill-color: #000 }
216110
.text-fill-white { -webkit-text-fill-color: #fff }
217111
.text-fill-gray { -webkit-text-fill-color: #9e9e9e }
218-
.text-fill { -webkit-text-fill-color: #38b2ac }
219112
220-
.text-stroke-transparent { -webkit-text-stroke-color: transparent }
221113
.text-stroke { -webkit-text-stroke-color: #38b2ac }
114+
.text-stroke-transparent { -webkit-text-stroke-color: transparent }
222115
223-
.text-stroke { -webkit-text-stroke-width: 1px }
116+
.text-stroke { -webkit-text-stroke-width: 1px; }
224117
.text-stroke-sm { -webkit-text-stroke-width: 2px }
225118
.text-stroke-md { -webkit-text-stroke-width: 4px }
226119
.text-stroke-lg { -webkit-text-stroke-width: 8px }
227120
228-
${ /* FIXME: Merging of configs not working */'' }
229-
.paint-fsm { paint-order: fill stroke markers }
230-
.paint-fms { paint-order: fill markers stroke }
231-
.paint-sfm { paint-order: stroke fill markers }
232-
.paint-smf { paint-order: stroke markers fill }
233-
.paint-mfs { paint-order: markers fill stroke }
234-
.paint-msf { paint-order: markers stroke fill }
235-
236121
.paint-stroke { paint-order: stroke }
237122
`
238123

239-
return generatePluginCss(tailwindConfig, testConfig).then(css => expect(css).toMatchCss(expectedCss))
124+
return postcss(tailwind(testConfig)).process('@tailwind utilities;', { from: undefined })
125+
.then((result) => expect(result.css).toMatchCss(expectedCss))
126+
})
127+
128+
test('variants can be customized', () => {
129+
const testConfig = {
130+
...commonConfig,
131+
safelist: [],
132+
content: [
133+
{ raw: String.raw`<div class="text-fill-white text-stroke sm:text-stroke-2 text-stroke-black hover:text-fill-gray-300 focus:text-stroke-gray-900"></div>` },
134+
],
135+
}
136+
const expectedCss = `
137+
.text-fill-white { -webkit-text-fill-color: #fff }
138+
.text-stroke { -webkit-text-stroke-color: #eeeeee }
139+
.text-stroke-black { -webkit-text-stroke-color: #000 }
140+
.text-stroke { -webkit-text-stroke-width: 1px }
141+
142+
.hover\\:text-fill-gray-300:hover { -webkit-text-fill-color: #e0e0e0 }
143+
.focus\\:text-stroke-gray-900:focus { -webkit-text-stroke-color: #212121 }
144+
145+
@media (min-width: 640px) {
146+
.sm\\:text-stroke-2 { -webkit-text-stroke-width: 2px }
147+
}
148+
`
149+
150+
return postcss(tailwind(testConfig)).process('@tailwind utilities;', { from: undefined })
151+
.then((result) => expect(result.css).toMatchCss(expectedCss))
152+
})
153+
154+
test('utilities accept arbitrary values', () => {
155+
const testConfig = {
156+
...commonConfig,
157+
safelist: [],
158+
content: [
159+
{ raw: String.raw`<div class="text-fill-[lime] text-stroke-[black] text-stroke-[0.25rem] paint-[stroke_fill_markers]"></div>` },
160+
{ raw: String.raw`<div class="text-fill-[lime] text-stroke-[color:black] text-stroke-[length:0.25rem] paint-[stroke_fill_markers]"></div>` },
161+
],
162+
}
163+
const expectedCss = `
164+
.text-fill-\\[lime\\] { -webkit-text-fill-color: lime }
165+
.text-stroke-\\[black\\] { -webkit-text-stroke-color: black }
166+
.text-stroke-\\[color\\:black\\] { -webkit-text-stroke-color: black }
167+
.text-stroke-\\[0\\.25rem\\] { -webkit-text-stroke-width: 0.25rem }
168+
.text-stroke-\\[length\\:0\\.25rem\\] { -webkit-text-stroke-width: 0.25rem }
169+
.paint-\\[stroke_fill_markers\\] { paint-order: stroke fill markers }
170+
`
171+
172+
return postcss(tailwind(testConfig)).process('@tailwind utilities;', { from: undefined })
173+
.then((result) => expect(result.css).toMatchCss(expectedCss))
174+
})
175+
176+
test('variants accept arbitrary values', () => {
177+
const testConfig = {
178+
...commonConfig,
179+
safelist: [],
180+
content: [
181+
{ raw: String.raw`<div class="[&>*]:text-fill-[lime]"></div>` },
182+
],
183+
}
184+
const expectedCss = `
185+
.\\[\\&\\>\\*\\]\\:text-fill-\\[lime\\] > * { -webkit-text-fill-color: lime }
186+
`
187+
188+
return postcss(tailwind(testConfig)).process('@tailwind utilities;', { from: undefined })
189+
.then((result) => expect(result.css).toMatchCss(expectedCss))
240190
})

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tailwindcss-text-fill-stroke",
3-
"version": "1.1.2",
3+
"version": "2.0.0-beta.1",
44
"description": "Text-fill and text-stroke utilities for Tailwind CSS.",
55
"keywords": [
66
"plugin",
@@ -29,10 +29,11 @@
2929
"test": "jest"
3030
},
3131
"dependencies": {
32-
"@hacknug/tailwindcss-plugin-utils": "^0.8.0"
32+
"flat": "5.0.2",
33+
"tailwindcss": "3.1.4"
3334
},
3435
"devDependencies": {
35-
"jest": "^28.1.2",
36-
"jest-matcher-css": "^1.1.0"
36+
"jest": "28.1.2",
37+
"jest-matcher-css": "1.1.0"
3738
}
3839
}

0 commit comments

Comments
 (0)