diff --git a/CHANGELOG.md b/CHANGELOG.md index c42dbd18a76a..2be85bf37b81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use local user CSS cache for `@apply` ([#7524](https://github.com/tailwindlabs/tailwindcss/pull/7524)) - Invalidate context when main CSS changes ([#7626](https://github.com/tailwindlabs/tailwindcss/pull/7626)) - Only add `!` to selector class matching template candidate when using important modifier with mutli-class selectors ([#7664](https://github.com/tailwindlabs/tailwindcss/pull/7664)) +- Correctly parse and prefix animation names with dots ([#7163](https://github.com/tailwindlabs/tailwindcss/pull/7163)) ### Changed diff --git a/src/corePlugins.js b/src/corePlugins.js index b9b9a340363a..ced2be2163e5 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -3,6 +3,7 @@ import * as path from 'path' import postcss from 'postcss' import createUtilityPlugin from './util/createUtilityPlugin' import buildMediaQuery from './util/buildMediaQuery' +import escapeClassName from './util/escapeClassName' import parseAnimationValue from './util/parseAnimationValue' import flattenColorPalette from './util/flattenColorPalette' import withAlphaVariable, { withAlphaValue } from './util/withAlphaVariable' @@ -612,8 +613,8 @@ export let corePlugins = { }) }, - animation: ({ matchUtilities, theme, prefix }) => { - let prefixName = (name) => prefix(`.${name}`).slice(1) + animation: ({ matchUtilities, theme, config }) => { + let prefixName = (name) => `${config('prefix')}${escapeClassName(name)}` let keyframes = Object.fromEntries( Object.entries(theme('keyframes') ?? {}).map(([key, value]) => { return [key, { [`@keyframes ${prefixName(key)}`]: value }] diff --git a/tests/animations.test.js b/tests/animations.test.js index 0a77a4c4e415..a1c580a79bd3 100644 --- a/tests/animations.test.js +++ b/tests/animations.test.js @@ -181,3 +181,96 @@ test('multiple custom', () => { `) }) }) + +test('with dots in the name', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-.5': 'zoom-.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes zoom-\.5 { + to { + transform: scale(0.5); + } + } + .animate-zoom-\.5 { + animation: zoom-\.5 2s; + } + @keyframes zoom-1\.5 { + to { + transform: scale(1.5); + } + } + .animate-zoom-1\.5 { + animation: zoom-1\.5 2s; + } + `) + }) +}) + +test('with dots in the name and prefix', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-.5': 'zoom-.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes tw-zoom-\.5 { + to { + transform: scale(0.5); + } + } + .tw-animate-zoom-\.5 { + animation: tw-zoom-\.5 2s; + } + @keyframes tw-zoom-1\.5 { + to { + transform: scale(1.5); + } + } + .tw-animate-zoom-1\.5 { + animation: tw-zoom-1\.5 2s; + } + `) + }) +})