diff --git a/__tests__/plugins/animation.test.js b/__tests__/plugins/animation.test.js new file mode 100644 index 000000000000..19409d52f535 --- /dev/null +++ b/__tests__/plugins/animation.test.js @@ -0,0 +1,92 @@ +import postcss from 'postcss' +import processPlugins from '../../src/util/processPlugins' +import plugin from '../../src/plugins/animation' + +function css(nodes) { + return postcss.root({ nodes }).toString() +} + +test('defining animation and keyframes', () => { + const config = { + theme: { + animation: { + none: 'none', + spin: 'spin 1s linear infinite', + ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + }, + keyframes: { + spin: { to: { transform: 'rotate(360deg)' } }, + ping: { '75%, 100%': { transform: 'scale(2)', opacity: '0' } }, + }, + }, + variants: { + animation: [], + }, + } + + const { utilities } = processPlugins([plugin()], config) + + expect(css(utilities)).toMatchCss(` + @layer utilities { + @variants { + @keyframes spin { + to { transform: rotate(360deg); } + } + @keyframes ping { + 75%, 100% { transform: scale(2); opacity: 0; } + } + } + } + + @layer utilities { + @variants { + .animate-none { animation: none; } + .animate-spin { animation: spin 1s linear infinite; } + .animate-ping { animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; } + } + } + `) +}) + +test('defining animation and keyframes with prefix', () => { + const config = { + prefix: 'tw-', + theme: { + animation: { + none: 'none', + spin: 'spin 1s linear infinite', + ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + }, + keyframes: { + spin: { to: { transform: 'rotate(360deg)' } }, + ping: { '75%, 100%': { transform: 'scale(2)', opacity: '0' } }, + }, + }, + variants: { + animation: [], + }, + } + + const { utilities } = processPlugins([plugin()], config) + + expect(css(utilities)).toMatchCss(` + @layer utilities { + @variants { + @keyframes tw-spin { + to { transform: rotate(360deg); } + } + @keyframes tw-ping { + 75%, 100% { transform: scale(2); opacity: 0; } + } + } + } + + @layer utilities { + @variants { + .tw-animate-none { animation: none; } + .tw-animate-spin { animation: tw-spin 1s linear infinite; } + .tw-animate-ping { animation: tw-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; } + } + } + `) +}) diff --git a/src/plugins/animation.js b/src/plugins/animation.js index 6a830674213a..c3a839b5a944 100644 --- a/src/plugins/animation.js +++ b/src/plugins/animation.js @@ -1,16 +1,26 @@ import _ from 'lodash' import nameClass from '../util/nameClass' +import parseAnimationValue from '../util/parseAnimationValue' export default function () { - return function ({ addUtilities, theme, variants }) { + return function ({ addUtilities, theme, variants, prefix }) { + const prefixName = (name) => prefix(`.${name}`).slice(1) const keyframesConfig = theme('keyframes') - const keyframesStyles = _.mapKeys(keyframesConfig, (_keyframes, name) => `@keyframes ${name}`) + const keyframesStyles = _.mapKeys( + keyframesConfig, + (_keyframes, name) => `@keyframes ${prefixName(name)}` + ) + addUtilities(keyframesStyles, { respectImportant: false }) const animationConfig = theme('animation') const utilities = _.mapValues( _.mapKeys(animationConfig, (_animation, suffix) => nameClass('animate', suffix)), - (animation) => ({ animation }) + (animation) => { + const { name } = parseAnimationValue(animation) + if (name === undefined) return { animation } + return { animation: animation.replace(name, prefixName(name)) } + } ) addUtilities(utilities, variants('animation')) }