@@ -11,7 +11,8 @@ import {
11
11
toaster ,
12
12
TextInput ,
13
13
Heading ,
14
- Text
14
+ Text ,
15
+ Switch
15
16
} from "evergreen-ui" ;
16
17
import { TailwindConverter , TailwindConverterConfig } from "css-to-tailwindcss" ;
17
18
@@ -25,13 +26,23 @@ const Monaco = dynamic(() => import("../components/Monaco"), {
25
26
interface RawSettings {
26
27
tailwindConfig ?: string ;
27
28
remInPx ?: string | null ;
29
+ arbitraryPropertiesIsEnabled ?: boolean ;
28
30
}
29
31
30
32
const evalConfig = ( configValue : string ) =>
31
33
eval ( `const module = {}; ${ configValue } ; module.exports;` ) ;
32
34
33
35
const DEFAULT_POSTCSS_PLUGINS = [ require ( "postcss-nested" ) ] ;
34
36
37
+ function decorateResult ( result : string ) {
38
+ return `/*
39
+ Based on TailwindCSS recommendations,
40
+ consider using classes instead of the \`@apply\` directive
41
+ @see https://tailwindcss.com/docs/reusing-styles#avoiding-premature-abstraction
42
+ */
43
+ ${ result } `;
44
+ }
45
+
35
46
function CssToTailwindSettings ( {
36
47
open,
37
48
toggle,
@@ -43,11 +54,16 @@ function CssToTailwindSettings({
43
54
onConfirm : ( props : {
44
55
tailwindConfig : string ;
45
56
remInPx : string ;
57
+ arbitraryPropertiesIsEnabled : boolean ;
46
58
} ) => boolean | Promise < boolean > ;
47
59
settings : RawSettings ;
48
60
} ) {
49
61
const [ tailwindConfig , setTailwindConfig ] = useState ( settings . tailwindConfig ) ;
50
62
const [ remInPx , setRemInPx ] = useState ( settings . remInPx ) ;
63
+ const [
64
+ arbitraryPropertiesIsEnabled ,
65
+ setArbitraryPropertiesIsEnabled
66
+ ] = useState ( settings . arbitraryPropertiesIsEnabled || false ) ;
51
67
52
68
return (
53
69
< Dialog
@@ -57,7 +73,8 @@ function CssToTailwindSettings({
57
73
onConfirm = { async close => {
58
74
const isSuccess = await onConfirm ( {
59
75
tailwindConfig,
60
- remInPx
76
+ remInPx,
77
+ arbitraryPropertiesIsEnabled
61
78
} ) ;
62
79
if ( isSuccess ) {
63
80
close ( ) ;
@@ -78,16 +95,38 @@ function CssToTailwindSettings({
78
95
placeholder = "Enter URL"
79
96
onChange = { e => setRemInPx ( e . target . value ) }
80
97
value = { remInPx || "" }
98
+ marginTop = "4px"
99
+ />
100
+
101
+ < Heading marginTop = { 24 } >
102
+ Enable arbitrary properties
103
+ < a
104
+ href = "https://tailwindcss.com/docs/adding-custom-styles#arbitrary-properties"
105
+ target = "_blank"
106
+ style = { { verticalAlign : "middle" } }
107
+ >
108
+ < Tooltip content = "Open the TailwindCSS docs..." >
109
+ < Icon icon = "help" color = "info" marginLeft = { 8 } size = { 16 } />
110
+ </ Tooltip >
111
+ </ a >
112
+ </ Heading >
113
+ < Switch
114
+ checked = { arbitraryPropertiesIsEnabled }
115
+ onChange = { e =>
116
+ setArbitraryPropertiesIsEnabled ( ( e . target as any ) . checked )
117
+ }
118
+ marginTop = "4px"
81
119
/>
82
- < Heading marginTop = { 30 } >
120
+
121
+ < Heading marginTop = { 24 } >
83
122
Tailwind configuration
84
123
< a
85
124
href = "https://tailwindcss.com/docs/configuration"
86
125
target = "_blank"
87
126
style = { { verticalAlign : "middle" } }
88
127
>
89
128
< Tooltip content = "Open the TailwindCSS docs..." >
90
- < Icon icon = "help" color = "info" marginLeft = { 16 } size = { 16 } />
129
+ < Icon icon = "help" color = "info" marginLeft = { 8 } size = { 16 } />
91
130
</ Tooltip >
92
131
</ a >
93
132
</ Heading >
@@ -124,7 +163,8 @@ export default function CssToTailwind3({ defaultSettings }) {
124
163
125
164
const converterConfig = useMemo ( ( ) => {
126
165
const config : Partial < TailwindConverterConfig > = {
127
- remInPx : rawSettings . remInPx ? parseInt ( rawSettings . remInPx , 10 ) : null
166
+ remInPx : rawSettings . remInPx ? parseInt ( rawSettings . remInPx , 10 ) : null ,
167
+ arbitraryPropertiesIsEnabled : ! ! rawSettings . arbitraryPropertiesIsEnabled
128
168
} ;
129
169
130
170
if ( isNaN ( config [ "remInPx" ] ) ) {
@@ -150,18 +190,29 @@ export default function CssToTailwind3({ defaultSettings }) {
150
190
} , [ rawSettings ] ) ;
151
191
152
192
const tailwindConverter = useMemo ( ( ) => {
153
- return new TailwindConverter ( {
154
- postCSSPlugins : DEFAULT_POSTCSS_PLUGINS ,
155
- ...converterConfig
156
- } ) ;
193
+ try {
194
+ return new TailwindConverter ( {
195
+ postCSSPlugins : DEFAULT_POSTCSS_PLUGINS ,
196
+ ...converterConfig
197
+ } ) ;
198
+ } catch ( e ) {
199
+ toaster . danger (
200
+ "Unable to create TailwindConverter. Invalid configuration passed" ,
201
+ {
202
+ description : e . message
203
+ }
204
+ ) ;
205
+
206
+ return new TailwindConverter ( { postCSSPlugins : DEFAULT_POSTCSS_PLUGINS } ) ;
207
+ }
157
208
} , [ converterConfig ] ) ;
158
209
159
210
const transformer = useCallback < Transformer > (
160
211
async ( { value } ) => {
161
212
try {
162
- return (
163
- await tailwindConverter . convertCSS ( value )
164
- ) . convertedRoot . toString ( ) ;
213
+ return decorateResult (
214
+ ( await tailwindConverter . convertCSS ( value ) ) . convertedRoot . toString ( )
215
+ ) ;
165
216
} catch ( e ) {
166
217
toaster . danger ( "Unable to convert CSS" , {
167
218
description : e . message
@@ -215,7 +266,8 @@ export async function getStaticProps() {
215
266
props : {
216
267
defaultSettings : {
217
268
tailwindConfig : rawTailwindConfig ,
218
- remInPx : "16"
269
+ remInPx : "16" ,
270
+ arbitraryPropertiesIsEnabled : false
219
271
} as RawSettings
220
272
}
221
273
} ;
0 commit comments