Skip to content

Commit

Permalink
support for modern import syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
heidkaemper committed Jan 27, 2025
1 parent 5c25ed1 commit 168936a
Show file tree
Hide file tree
Showing 31 changed files with 542 additions and 268 deletions.
3 changes: 2 additions & 1 deletion jest/content/iteration-count.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<div class="animate-infinite"></div>
<div class="animate-once"></div>
<div class="animate-iteration-[7]"></div>
<div class="animate-iteration-7"></div>
<div class="animate-iteration-[14]"></div>
24 changes: 24 additions & 0 deletions jest/customMatchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
expect.extend({
toIncludeAll(received, expected) {
function stripped(str) {
return str.replace(/\s/g, '').replace(/;/g, '')
}

const receivedStripped = stripped(received)

const pass = Array.isArray(expected) && expected.every(value => receivedStripped.includes(stripped(value)))

return {
pass,
message: () => pass
? this.utils.matcherHint('.not.toIncludeAll') +
'\n\n' +
`Expected not to have all of: ${this.utils.printExpected(received)}\n` +
`Received: ${this.utils.printReceived(expected)}`
: this.utils.matcherHint('.toIncludeAll') +
'\n\n' +
`Expected to have all of: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`,
}
},
})
185 changes: 69 additions & 116 deletions jest/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,151 +2,104 @@ const path = require('path')
const postcss = require('postcss')
const tailwindcss = require('@tailwindcss/postcss')

async function run(file) {
async function run(file, options = {}) {
const { currentTestName } = expect.getState()

const result = await postcss(tailwindcss()).process(`
@import 'tailwindcss/utilities' source(none);
@plugin './../src/';
@source './${file}';
`, {
const config = [
options.scope
? `@import "tailwindcss/${options.scope}" source(none);`
: '@import "tailwindcss" source(none);',
options?.importType === 'legacy'
? '@plugin "./../src/";'
: '@import "./../src/";',
`@source "./${file}";`,
].join('\n')

const result = await postcss(tailwindcss()).process(config, {
from: `${path.resolve(__filename)}?test=${currentTestName}`,
})

return result.css.replace(/^\/\*!.*?\n/, '').trim()
return result.css
}

it('generates `delay` utilities', async () => {
expect(await run('content/delay.html')).toMatchInlineSnapshot(`
".animate-delay-75 {
--tw-animate-delay: 75ms;
animation-delay: var(--tw-animate-delay);
}
.animate-delay-333 {
--tw-animate-delay: 333ms;
animation-delay: var(--tw-animate-delay);
}
.animate-delay-\\[666ms\\] {
--tw-animate-delay: 666ms;
animation-delay: var(--tw-animate-delay);
}"
`)
expect(await run('content/delay.html', { scope: 'utilities' })).toIncludeAll([
'.animate-delay-75 { animation-delay: 75ms; }',
'.animate-delay-333 { animation-delay: 333ms; }',
'.animate-delay-\\[666ms\\] { animation-delay: 666ms; }',
])
})

it('generates `duration` utilities', async () => {
expect(await run('content/duration.html')).toMatchInlineSnapshot(`
".animate-duration-75 {
--tw-animate-duration: 75ms;
animation-duration: var(--tw-animate-duration);
}
.animate-duration-333 {
--tw-animate-duration: 333ms;
animation-duration: var(--tw-animate-duration);
}
.animate-duration-\\[666ms\\] {
--tw-animate-duration: 666ms;
animation-duration: var(--tw-animate-duration);
}"
`)
expect(await run('content/duration.html', { scope: 'utilities' })).toIncludeAll([
'.animate-duration-75 { animation-duration: 75ms; }',
'.animate-duration-333 { animation-duration: 333ms; }',
'.animate-duration-\\[666ms\\] { animation-duration: 666ms; }',
])
})

it('generates `direction` utilities', async () => {
expect(await run('content/direction.html')).toMatchInlineSnapshot(`
".animate-normal {
--tw-animate-direction: normal;
animation-direction: var(--tw-animate-direction);
}
.animate-reverse {
--tw-animate-direction: reverse;
animation-direction: var(--tw-animate-direction);
}"
`)
expect(await run('content/direction.html', { scope: 'utilities' })).toIncludeAll([
'.animate-normal { animation-direction: normal; }',
'.animate-reverse { animation-direction: reverse; }',
])
})

it('generates `fill-mode` utilities', async () => {
expect(await run('content/fill-mode.html')).toMatchInlineSnapshot(`
".animate-fill-both {
--tw-animate-fill: both;
animation-fill-mode: var(--tw-animate-fill);
}
.animate-fill-none {
--tw-animate-fill: normal;
animation-fill-mode: var(--tw-animate-fill);
}"
`)
expect(await run('content/fill-mode.html', { scope: 'utilities' })).toIncludeAll([
'.animate-fill-both { animation-fill-mode: both; }',
'.animate-fill-none { animation-fill-mode: normal; }',
])
})

it('generates `iteration-count` utilities', async () => {
expect(await run('content/iteration-count.html')).toMatchInlineSnapshot(`
".animate-infinite {
--tw-animate-iteration: infinite;
animation-iteration-count: var(--tw-animate-iteration);
}
.animate-iteration-\\[7\\] {
--tw-animate-iteration: 7;
animation-iteration-count: var(--tw-animate-iteration);
}
.animate-once {
--tw-animate-iteration: 1;
animation-iteration-count: var(--tw-animate-iteration);
}"
`)
expect(await run('content/iteration-count.html', { scope: 'utilities' })).toIncludeAll([
'.animate-infinite { animation-iteration-count: infinite; }',
'.animate-once { animation-iteration-count: 1; }',
'.animate-iteration-7 { animation-iteration-count: 7; }',
'.animate-iteration-\\[14\\] { animation-iteration-count: 14; }',
])
})

it('generates `play-state` utilities', async () => {
expect(await run('content/play-state.html')).toMatchInlineSnapshot(`
".animate-play {
--tw-animate-state: running;
animation-play-state: var(--tw-animate-state);
}
.animate-stop {
--tw-animate-state: paused;
animation-play-state: var(--tw-animate-state);
}"
`)
expect(await run('content/play-state.html', { scope: 'utilities' })).toIncludeAll([
'.animate-play { animation-play-state: running; }',
'.animate-stop { animation-play-state: paused; }',
])
})

it('generates `timing-function` utilities', async () => {
expect(await run('content/timing-function.html')).toMatchInlineSnapshot(`
".animate-ease {
--tw-animate-easing: ease;
animation-timing-function: var(--tw-animate-easing);
}
.animate-ease-\\[cubic-bezier\\(1\\,0\\.66\\,0\\.33\\,0\\)\\] {
--tw-animate-easing: cubic-bezier(1,0.66,0.33,0);
animation-timing-function: var(--tw-animate-easing);
}
.animate-ease-linear {
--tw-animate-easing: linear;
animation-timing-function: var(--tw-animate-easing);
}"
`)
expect(await run('content/timing-function.html', { scope: 'utilities' })).toIncludeAll([
'.animate-ease { animation-timing-function: ease; }',
'.animate-ease-linear { animation-timing-function: linear; }',
'.animate-ease-\\[cubic-bezier\\(1\\,0\\.66\\,0\\.33\\,0\\)\\] { animation-timing-function: cubic-bezier(1,0.66,0.33,0); }',
])
})

it('generates `composition` utilities', async () => {
expect(await run('content/composition.html')).toMatchInlineSnapshot(`
".animate-accumulate {
--tw-animate-composition: accumulate;
animation-composition: var(--tw-animate-composition);
}
.animate-add {
--tw-animate-composition: add;
animation-composition: var(--tw-animate-composition);
}
.animate-replace {
--tw-animate-composition: replace;
animation-composition: var(--tw-animate-composition);
}"
`)
expect(await run('content/composition.html', { scope: 'utilities' })).toIncludeAll([
'.animate-add { animation-composition: add; }',
'.animate-replace { animation-composition: replace; }',
'.animate-accumulate { animation-composition: accumulate; }',
])
})

it('generates predefined animations for modern import', async () => {
expect(await run('content/predefined-animations.html', { importType: 'modern' })).toIncludeAll([
'.animate-fade { animation: var(--animate-fade); }',
'--animate-fade: fade var(--default-animation-duration, 1s) var(--default-animation-timing-function, ease) var(--default-animation-delay, 0s) both;',
'@keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; }}',
'.animate-spin { animation: var(--animate-spin); }',
'--animate-spin: spin var(--default-animation-duration, 1s) var(--default-animation-timing-function, linear) var(--default-animation-delay, 0s) infinite;',
'@keyframes spin { to { transform: rotate(360deg); }}',
])
})

it('generates predefined animations', async () => {
expect(await run('content/predefined-animations.html')).toMatchInlineSnapshot(`
".animate-fade {
animation: fade var(--tw-animate-duration, 1s) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, 1) var(--tw-animate-fill, both);
}
.animate-spin {
animation: spin var(--tw-animate-duration, 1s) var(--tw-animate-easing, linear) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, infinite) var(--tw-animate-fill, none);
}"
`)
it('generates predefined animations for legacy import', async () => {
expect(await run('content/predefined-animations.html', { importType: 'legacy' })).toIncludeAll([
'.animate-fade { animation: fade var(--default-animation-duration, 1s) var(--default-animation-timing-function, ease) var(--default-animation-delay, 0s) both; }',
'@keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; }}',
'.animate-spin { animation: spin var(--default-animation-duration, 1s) var(--default-animation-timing-function, linear) var(--default-animation-delay, 0s) infinite; }',
'@keyframes spin { to { transform: rotate(360deg); }}',
])
})
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
],
"main": "src/index.js",
"types": "src/index.d.ts",
"style": "src/index.css",
"scripts": {
"watch": "npm run dev -- -w",
"dev": "npx @tailwindcss/cli -i resources/app.css -o public/app.css",
"test": "jest",
"test": "jest --setupFilesAfterEnv '<rootDir>/jest/customMatchers.js'",
"lint": "npx eslint {src,jest}/**",
"lint:fix": "npx eslint {src,jest}/** --fix"
},
Expand All @@ -39,7 +40,6 @@
"eslint-plugin-jest": "^28.11.0",
"jest": "^29.7.0",
"postcss": "^8.5.1",
"prettier": "^2.8.8",
"tailwindcss": "^4.0.0"
}
}
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</head>

<body class="p-8 flex justify-center items-center">
<h1 class="font-bold text-5xl animate-wiggle animate-infinite animate-delay-42">
<h1 class="font-bold text-5xl animate-wiggle animate-infinite">
Test file for development
</h1>
</body>
Expand Down
6 changes: 4 additions & 2 deletions resources/app.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import "tailwindcss" source("../public");
@import "tailwindcss" source(none);

@plugin "../src";
@import "../src/";

@source "../public/index.html"
13 changes: 13 additions & 0 deletions src/compat/composition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = ({ addUtilities }) => {
addUtilities({
'.animate-replace': {
'animation-composition': 'replace',
},
'.animate-add': {
'animation-composition': 'add',
},
'.animate-accumulate': {
'animation-composition': 'accumulate',
},
})
}
3 changes: 1 addition & 2 deletions src/utilities/delay.js → src/compat/delay.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module.exports = ({ matchUtilities, theme }) => matchUtilities({
'animate-delay': value => ({
'--tw-animate-delay': value,
'animation-delay': 'var(--tw-animate-delay)',
'animation-delay': value,
}),
}, {
values: theme('animationDelay'),
Expand Down
14 changes: 14 additions & 0 deletions src/compat/direction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = ({ addUtilities }) => addUtilities({
'.animate-normal': {
'animation-direction': 'normal',
},
'.animate-reverse': {
'animation-direction': 'reverse',
},
'.animate-alternate': {
'animation-direction': 'alternate',
},
'.animate-alternate-reverse': {
'animation-direction': 'alternate-reverse',
},
})
3 changes: 1 addition & 2 deletions src/utilities/duration.js → src/compat/duration.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module.exports = ({ matchUtilities, theme }) => matchUtilities({
'animate-duration': value => ({
'--tw-animate-duration': value,
'animation-duration': 'var(--tw-animate-duration)',
'animation-duration': value,
}),
}, {
values: theme('animationDuration'),
Expand Down
14 changes: 14 additions & 0 deletions src/compat/fill-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = ({ addUtilities }) => addUtilities({
'.animate-fill-none': {
'animation-fill-mode': 'normal',
},
'.animate-fill-forwards': {
'animation-fill-mode': 'forwards',
},
'.animate-fill-backwards': {
'animation-fill-mode': 'backwards',
},
'.animate-fill-both': {
'animation-fill-mode': 'both',
},
})
24 changes: 24 additions & 0 deletions src/compat/iteration-count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = ({ addUtilities, matchUtilities, theme }) => {
addUtilities({
'.animate-infinite': {
'animation-iteration-count': 'infinite',
},
'.animate-once': {
'animation-iteration-count': '1',
},
'.animate-twice': {
'animation-iteration-count': '2',
},
'.animate-thrice': {
'animation-iteration-count': '3',
},
})

matchUtilities({
'animate-iteration': value => ({
'animation-iteration-count': value,
}),
}, {
values: theme('animationIteration'),
})
}
14 changes: 14 additions & 0 deletions src/compat/play-state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = ({ addUtilities }) => addUtilities({
'.animate-run': {
'animation-play-state': 'running',
},
'.animate-play': {
'animation-play-state': 'running',
},
'.animate-stop': {
'animation-play-state': 'paused',
},
'.animate-pause': {
'animation-play-state': 'paused',
},
})
Loading

0 comments on commit 168936a

Please sign in to comment.