Skip to content

Commit

Permalink
feat!: add the ability to convert non-convertible properties as "arbi…
Browse files Browse the repository at this point in the history
…trary properties" using the `arbitraryPropertiesIsEnabled` parameter
  • Loading branch information
Jackardios committed Feb 1, 2023
1 parent aac39f0 commit 4f7a26a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 43 deletions.
11 changes: 10 additions & 1 deletion src/TailwindConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from './utils/converterMappingByTailwindTheme';
import {
convertDeclarationValue,
prepareArbitraryValue,
TAILWIND_DECLARATION_CONVERTERS,
} from './constants/converters';
import { isChildNode } from './utils/isChildNode';
Expand All @@ -36,6 +37,7 @@ export interface TailwindConverterConfig {
remInPx?: number | null;
tailwindConfig?: Config;
postCSSPlugins: AcceptedPlugin[];
arbitraryPropertiesIsEnabled: boolean;
}

export interface ResolvedTailwindConverterConfig
Expand All @@ -49,6 +51,7 @@ export const DEFAULT_CONVERTER_CONFIG: Omit<
'tailwindConfig'
> = {
postCSSPlugins: [],
arbitraryPropertiesIsEnabled: false,
};

export class TailwindConverter {
Expand Down Expand Up @@ -147,12 +150,18 @@ export class TailwindConverter {
}

protected convertDeclarationToClasses(declaration: Declaration) {
const classes =
let classes =
TAILWIND_DECLARATION_CONVERTERS[declaration.prop]?.(
declaration,
this.config
) || [];

if (classes.length === 0 && this.config.arbitraryPropertiesIsEnabled) {
classes = [
`[${declaration.prop}:${prepareArbitraryValue(declaration.value)}]`,
];
}

return this.config.tailwindConfig.prefix
? classes.map(
className => `${this.config.tailwindConfig.prefix}${className}`
Expand Down
2 changes: 1 addition & 1 deletion src/constants/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { parseCSSFunctions } from '../utils/parseCSSFunctions';
import { removeUnnecessarySpaces } from '../utils/removeUnnecessarySpaces';
import { isCSSVariable } from '../utils/isCSSVariable';

function prepareArbitraryValue(value: string) {
export function prepareArbitraryValue(value: string) {
return normalizeValue(value).replace(/_/g, '\\_').replace(/\s+/g, '_');
}

Expand Down
105 changes: 69 additions & 36 deletions test/TailwindConverter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ const simpleCSS = `
.foo {
text-align: center;
font-size: 12px;
animation-delay: 200ms;
&:hover {
filter: blur(4px) brightness(0.5) sepia(100%) contrast(1) hue-rotate(30deg)
invert(0) opacity(0.05) saturate(1.5);
transform: translateX(12px) translateY(0.5em) translateZ(0.5rem)
scaleY(0.725) rotate(124deg);
font-size: 16px;
}
Expand Down Expand Up @@ -119,6 +122,72 @@ describe('TailwindConverter', () => {
]);
});

it('should convert unconvertible declarations if `arbitraryPropertiesIsEnabled` config is enabled', async () => {
const converter = createTailwindConverter({
arbitraryPropertiesIsEnabled: true,
});
const converted = await converter.convertCSS(simpleCSS);

expect(converted.convertedRoot.toString()).toMatchSnapshot();
expect(converted.nodes).toEqual([
{
rule: expect.objectContaining({ selector: '.foo' }),
tailwindClasses: [
'text-center',
'text-xs',
'[animation-delay:200ms]',
'hover:blur-sm',
'hover:brightness-50',
'hover:sepia',
'hover:contrast-100',
'hover:hue-rotate-30',
'hover:invert-0',
'hover:opacity-5',
'hover:saturate-150',
'hover:[transform:translateX(12px)_translateY(0.5em)_translateZ(0.5rem)_scaleY(0.725)_rotate(124deg)]',
'hover:text-base',
'md:font-semibold',
],
},
]);
});

it('should return an empty result when converting an empty string', async () => {
const converter = createTailwindConverter();
const converted = await converter.convertCSS('');

expect(converted.convertedRoot.toString()).toEqual('');
expect(converted.nodes).toEqual([]);
});

it('should convert the css part string', async () => {
const converter = createTailwindConverter();
const converted = await converter.convertCSS(
'{ text-align: center; font-size: 12px; &:hover { font-size: 16px; } @media screen and (min-width: 768px) { font-weight: 600; } }'
);
expect(converted.convertedRoot.toString()).toMatchSnapshot();
expect(converted.nodes).toEqual([
expect.objectContaining({
rule: expect.objectContaining({ selector: '' }),
tailwindClasses: [
'text-center',
'text-xs',
'hover:text-base',
'md:font-semibold',
],
}),
]);
});

it('should throw an error when converting invalid css string', async () => {
const converter = createTailwindConverter();
await expect(
converter.convertCSS(
'some invalid css string... .some-class { display: block; } ...'
)
).rejects.toThrow(Error);
});

it('should convert the complex CSS', async () => {
const converter = createTailwindConverter();
const converted = await converter.convertCSS(complexCSS);
Expand Down Expand Up @@ -434,40 +503,4 @@ describe('TailwindConverter', () => {
},
]);
});

it('should return an empty result when converting an empty string', async () => {
const converter = createTailwindConverter();
const converted = await converter.convertCSS('');

expect(converted.convertedRoot.toString()).toEqual('');
expect(converted.nodes).toEqual([]);
});

it('should convert the css part string', async () => {
const converter = createTailwindConverter();
const converted = await converter.convertCSS(
'{ text-align: center; font-size: 12px; &:hover { font-size: 16px; } @media screen and (min-width: 768px) { font-weight: 600; } }'
);
expect(converted.convertedRoot.toString()).toMatchSnapshot();
expect(converted.nodes).toEqual([
expect.objectContaining({
rule: expect.objectContaining({ selector: '' }),
tailwindClasses: [
'text-center',
'text-xs',
'hover:text-base',
'md:font-semibold',
],
}),
]);
});

it('should throw an error when converting invalid css string', async () => {
const converter = createTailwindConverter();
await expect(
converter.convertCSS(
'some invalid css string... .some-class { display: block; } ...'
)
).rejects.toThrow(Error);
});
});
27 changes: 22 additions & 5 deletions test/__snapshots__/TailwindConverter.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

exports[`TailwindConverter should consider \`prefix\`, \`separator\` and \`corePlugins\` configurations 1`] = `
".foo {
@apply tw-text-center tw-text-xs hover_tw-blur-sm hover_tw-brightness-50 hover_tw-sepia hover_tw-contrast-100 hover_tw-hue-rotate-30 hover_tw-invert-0 hover_tw-opacity-5 hover_tw-saturate-150 hover_tw-text-base;
@apply tw-text-center tw-text-xs hover_tw-blur-sm hover_tw-brightness-50 hover_tw-sepia hover_tw-contrast-100 hover_tw-hue-rotate-30 hover_tw-invert-0 hover_tw-opacity-5 hover_tw-saturate-150 hover_tw-text-base;
animation-delay: 200ms;
}
.foo:hover {
transform: translateX(12px) translateY(0.5em) translateZ(0.5rem)
scaleY(0.725) rotate(124deg);
}
@media screen and (min-width: 768px) {
.foo {
font-weight: 600
}
.foo {
font-weight: 600
}
}
"
`;
Expand Down Expand Up @@ -149,7 +154,19 @@ exports[`TailwindConverter should convert the css part string 1`] = `

exports[`TailwindConverter should convert the simple CSS 1`] = `
".foo {
@apply text-center text-xs hover:blur-sm hover:brightness-50 hover:sepia hover:contrast-100 hover:hue-rotate-30 hover:invert-0 hover:opacity-5 hover:saturate-150 hover:text-base md:font-semibold;
@apply text-center text-xs hover:blur-sm hover:brightness-50 hover:sepia hover:contrast-100 hover:hue-rotate-30 hover:invert-0 hover:opacity-5 hover:saturate-150 hover:text-base md:font-semibold;
animation-delay: 200ms;
}
.foo:hover {
transform: translateX(12px) translateY(0.5em) translateZ(0.5rem)
scaleY(0.725) rotate(124deg);
}
"
`;

exports[`TailwindConverter should convert unconvertible declarations if \`arbitraryPropertiesIsEnabled\` config is enabled 1`] = `
".foo {
@apply text-center text-xs [animation-delay:200ms] hover:blur-sm hover:brightness-50 hover:sepia hover:contrast-100 hover:hue-rotate-30 hover:invert-0 hover:opacity-5 hover:saturate-150 hover:[transform:translateX(12px)_translateY(0.5em)_translateZ(0.5rem)_scaleY(0.725)_rotate(124deg)] hover:text-base md:font-semibold;
}
"
`;

0 comments on commit 4f7a26a

Please sign in to comment.