@@ -11,7 +11,8 @@ import {
1111 toaster ,
1212 TextInput ,
1313 Heading ,
14- Text
14+ Text ,
15+ Switch
1516} from "evergreen-ui" ;
1617import { TailwindConverter , TailwindConverterConfig } from "css-to-tailwindcss" ;
1718
@@ -25,13 +26,23 @@ const Monaco = dynamic(() => import("../components/Monaco"), {
2526interface RawSettings {
2627 tailwindConfig ?: string ;
2728 remInPx ?: string | null ;
29+ arbitraryPropertiesIsEnabled ?: boolean ;
2830}
2931
3032const evalConfig = ( configValue : string ) =>
3133 eval ( `const module = {}; ${ configValue } ; module.exports;` ) ;
3234
3335const DEFAULT_POSTCSS_PLUGINS = [ require ( "postcss-nested" ) ] ;
3436
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+
3546function CssToTailwindSettings ( {
3647 open,
3748 toggle,
@@ -43,11 +54,16 @@ function CssToTailwindSettings({
4354 onConfirm : ( props : {
4455 tailwindConfig : string ;
4556 remInPx : string ;
57+ arbitraryPropertiesIsEnabled : boolean ;
4658 } ) => boolean | Promise < boolean > ;
4759 settings : RawSettings ;
4860} ) {
4961 const [ tailwindConfig , setTailwindConfig ] = useState ( settings . tailwindConfig ) ;
5062 const [ remInPx , setRemInPx ] = useState ( settings . remInPx ) ;
63+ const [
64+ arbitraryPropertiesIsEnabled ,
65+ setArbitraryPropertiesIsEnabled
66+ ] = useState ( settings . arbitraryPropertiesIsEnabled || false ) ;
5167
5268 return (
5369 < Dialog
@@ -57,7 +73,8 @@ function CssToTailwindSettings({
5773 onConfirm = { async close => {
5874 const isSuccess = await onConfirm ( {
5975 tailwindConfig,
60- remInPx
76+ remInPx,
77+ arbitraryPropertiesIsEnabled
6178 } ) ;
6279 if ( isSuccess ) {
6380 close ( ) ;
@@ -78,16 +95,38 @@ function CssToTailwindSettings({
7895 placeholder = "Enter URL"
7996 onChange = { e => setRemInPx ( e . target . value ) }
8097 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"
81119 />
82- < Heading marginTop = { 30 } >
120+
121+ < Heading marginTop = { 24 } >
83122 Tailwind configuration
84123 < a
85124 href = "https://tailwindcss.com/docs/configuration"
86125 target = "_blank"
87126 style = { { verticalAlign : "middle" } }
88127 >
89128 < 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 } />
91130 </ Tooltip >
92131 </ a >
93132 </ Heading >
@@ -124,7 +163,8 @@ export default function CssToTailwind3({ defaultSettings }) {
124163
125164 const converterConfig = useMemo ( ( ) => {
126165 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
128168 } ;
129169
130170 if ( isNaN ( config [ "remInPx" ] ) ) {
@@ -150,18 +190,29 @@ export default function CssToTailwind3({ defaultSettings }) {
150190 } , [ rawSettings ] ) ;
151191
152192 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+ }
157208 } , [ converterConfig ] ) ;
158209
159210 const transformer = useCallback < Transformer > (
160211 async ( { value } ) => {
161212 try {
162- return (
163- await tailwindConverter . convertCSS ( value )
164- ) . convertedRoot . toString ( ) ;
213+ return decorateResult (
214+ ( await tailwindConverter . convertCSS ( value ) ) . convertedRoot . toString ( )
215+ ) ;
165216 } catch ( e ) {
166217 toaster . danger ( "Unable to convert CSS" , {
167218 description : e . message
@@ -215,7 +266,8 @@ export async function getStaticProps() {
215266 props : {
216267 defaultSettings : {
217268 tailwindConfig : rawTailwindConfig ,
218- remInPx : "16"
269+ remInPx : "16" ,
270+ arbitraryPropertiesIsEnabled : false
219271 } as RawSettings
220272 }
221273 } ;
0 commit comments