tailwindcss-animated
Advanced tools
| module.exports = ({ addUtilities, matchUtilities, theme }) => { | ||
| addUtilities({ | ||
| '.animate-replace': { | ||
| '--tw-animate-composition': 'replace', | ||
| 'animation-composition': 'var(--tw-animate-composition)', | ||
| }, | ||
| '.animate-add': { | ||
| '--tw-animate-composition': 'add', | ||
| 'animation-composition': 'var(--tw-animate-composition)', | ||
| }, | ||
| '.animate-accumulate': { | ||
| '--tw-animate-composition': 'accumulate', | ||
| 'animation-composition': 'var(--tw-animate-composition)', | ||
| }, | ||
| }) | ||
| matchUtilities({ | ||
| animate: value => { | ||
| const properties = value.split(/ +(?![^(]*\))/g) | ||
| if (properties.includes('replace') || properties.includes('add') || properties.includes('accumulate')) { | ||
| return | ||
| } | ||
| return { | ||
| 'animation-composition': 'var(--tw-animate-composition)', | ||
| } | ||
| }, | ||
| }, { | ||
| values: theme('animation'), | ||
| }) | ||
| } |
+9
-5
@@ -24,5 +24,7 @@ { | ||
| "scripts": { | ||
| "watch": "npm run dev -- -w", | ||
| "dev": "tailwindcss -o dist/tailwind.css", | ||
| "test": "jest --setupFilesAfterEnv '<rootDir>/jest/customMatchers.js'", | ||
| "eslint": "npx eslint src/**", | ||
| "eslint:fix": "npx eslint src/** --fix" | ||
| "eslint": "npx eslint {src,jest}/**", | ||
| "eslint:fix": "npx eslint {src,jest}/** --fix" | ||
| }, | ||
@@ -33,8 +35,10 @@ "peerDependencies": { | ||
| "devDependencies": { | ||
| "eslint": "^8.40.0", | ||
| "jest": "^29.5.0", | ||
| "@eslint/js": "^9.3.0", | ||
| "eslint": "^9.3.0", | ||
| "eslint-plugin-jest": "^28.5.0", | ||
| "jest": "^29.7.0", | ||
| "prettier": "^2.8.8", | ||
| "tailwindcss": "^3.1.0" | ||
| }, | ||
| "version": "1.0.1" | ||
| "version": "1.1.0" | ||
| } |
+60
-13
@@ -6,3 +6,2 @@ # Tailwind CSS Animated | ||
| ## Installation | ||
@@ -28,3 +27,2 @@ | ||
| ## Usage | ||
@@ -65,2 +63,3 @@ | ||
| | animate-duration-1000 | animation-duration: 1000ms; | | ||
| | animate-duration-\[5s\] [*](#arbitrary-values) | animation-duration: 5s; | | ||
@@ -80,3 +79,13 @@ ### Delay | ||
| | animate-delay-1000 | animation-delay: 1000ms; | | ||
| | animate-delay-\[5s\] [*](#arbitrary-values) | animation-delay: 5s; | | ||
| ### Direction | ||
| | Class | Properties | | ||
| |-----|-----| | ||
| | animate-normal | animation-direction: normal; | | ||
| | animate-reverse | animation-direction: reverse; | | ||
| | animate-alternate | animation-direction: alternate; | | ||
| | animate-alternate-reverse | animation-direction: alternate-reverse; | | ||
| ### Iteration Count | ||
@@ -90,12 +99,4 @@ | ||
| | animate-thrice | animation-iteration-count: 3; | | ||
| | animate-iteration-\[10\] [*](#arbitrary-values) | animation-iteration-count: 10; | | ||
| ### Direction | ||
| | Class | Properties | | ||
| |-----|-----| | ||
| | animate-normal | animation-direction: normal; | | ||
| | animate-reverse | animation-direction: reverse; | | ||
| | animate-alternate | animation-direction: alternate; | | ||
| | animate-alternate-reverse | animation-direction: alternate-reverse; | | ||
| ### Timing Function | ||
@@ -105,2 +106,3 @@ | ||
| |-----|-----| | ||
| | animate-ease | animation-timing-function: ease; | | ||
| | animate-ease-linear | animation-timing-function: linear; | | ||
@@ -110,2 +112,3 @@ | animate-ease-in | animation-timing-function: cubic-bezier(0.4, 0, 1, 1); | | ||
| | animate-ease-in-out | animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | | ||
| | animate-ease-\[cubic-bezier(1,1,0,0)\] [*](#arbitrary-values) | animation-timing-function: cubic-bezier(1, 1, 0, 0); | | ||
@@ -130,2 +133,10 @@ ### Fill Mode | ||
| ### Composition | ||
| | Class | Properties | | ||
| |-----|-----| | ||
| | animate-replace | animation-composition: replace; | | ||
| | animate-add | animation-composition: add; | | ||
| | animate-accumulate | animation-composition: accumulate; | | ||
| ## Variant modifiers and breakpoints | ||
@@ -143,6 +154,6 @@ | ||
| You can create custom properies on the fly by using square brackets. This works for Delay and Durations values. | ||
| This plugin uses the Just-in-Time (JIT) engine, which allows you to use [arbitrary values](https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values) for most animation properties. | ||
| ```html | ||
| <div class="animate-delay-[85ms] animate-duration-[2s]"> | ||
| <div class="animate-delay-[85ms] animate-duration-[2s] animate-iteration-[10]"> | ||
| <!-- ... --> | ||
@@ -179,1 +190,37 @@ </div> | ||
| Take a look at [src/theme.js](https://github.com/new-data-services/tailwindcss-animated/blob/main/src/theme.js) for the default settings. | ||
| ## FAQ | ||
| ### How to animate on scroll? | ||
| To run animations when an element enters the viewport, you need JavaScript. (At least until [animation-timeline](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline) has good browser support) | ||
| A good starting point for a JavaScript solution would be the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Or tools that build on it, such as the [Alpine.js Intersect plugin](https://alpinejs.dev/plugins/intersect) and the [Tailwind CSS Intersection plugin](https://github.com/heidkaemper/tailwindcss-intersect), to name just two. | ||
| ### Does this work with the Play CDN? | ||
| Unfortunately not. The Tailwind CSS Play CDN currently does not support third-party plugins. | ||
| ### How to combine multiple animations? | ||
| The simplest approach is to nest two elements: | ||
| ```html | ||
| <div class="animate-pulse"> | ||
| <div class="animate-bounce"></div> | ||
| </div> | ||
| ``` | ||
| ### Can keyframes and offset values be changed? | ||
| Offset positions of predefined animations can't be changed on the fly. But the behavior can still be modified with [animation-composition](#composition) utilities. | ||
| If you need more details on how compositions work, check out the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition). | ||
| --- | ||
| <a href="https://tailwindcss.com/"><img src="https://img.shields.io/badge/Tailwind%20CSS-3.1+-38bdf8?style=for-the-badge"></a> | ||
| <a href="https://www.npmjs.com/package/tailwindcss-animated"><img src="https://img.shields.io/npm/v/tailwindcss-animated?style=for-the-badge"></a> | ||
| <a href="https://www.npmjs.com/package/tailwindcss-animated"><img src="https://img.shields.io/npm/dt/tailwindcss-animated?style=for-the-badge"></a> |
+10
-9
@@ -1,13 +0,14 @@ | ||
| const plugin = require('tailwindcss/plugin'); | ||
| const plugin = require('tailwindcss/plugin') | ||
| module.exports = plugin(api => { | ||
| require('./utilities/delay')(api); | ||
| require('./utilities/direction')(api); | ||
| require('./utilities/duration')(api); | ||
| require('./utilities/fillMode')(api); | ||
| require('./utilities/iterationCount')(api); | ||
| require('./utilities/playState')(api); | ||
| require('./utilities/timingFunction')(api); | ||
| require('./utilities/composition')(api) | ||
| require('./utilities/delay')(api) | ||
| require('./utilities/direction')(api) | ||
| require('./utilities/duration')(api) | ||
| require('./utilities/fillMode')(api) | ||
| require('./utilities/iterationCount')(api) | ||
| require('./utilities/playState')(api) | ||
| require('./utilities/timingFunction')(api) | ||
| }, { | ||
| theme: require('./theme'), | ||
| }); | ||
| }) |
+60
-40
| module.exports = { | ||
| extend: { | ||
| animationDelay: { | ||
| none: '0ms', | ||
| 0: '0ms', | ||
| 75: '75ms', | ||
| 100: '100ms', | ||
| 150: '150ms', | ||
| 200: '200ms', | ||
| 300: '300ms', | ||
| 500: '500ms', | ||
| 700: '700ms', | ||
| 1000: '1000ms', | ||
| }, | ||
| animationDuration: { | ||
| 75: '75ms', | ||
| 100: '100ms', | ||
| 150: '150ms', | ||
| 200: '200ms', | ||
| 300: '300ms', | ||
| 500: '500ms', | ||
| 700: '700ms', | ||
| 1000: '1000ms', | ||
| }, | ||
| animationTimingFunction: { | ||
| DEFAULT: 'ease', | ||
| 'linear': 'linear', | ||
| 'in': 'cubic-bezier(0.4, 0, 1, 1)', | ||
| 'out': 'cubic-bezier(0, 0, 0.2, 1)', | ||
| 'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)', | ||
| }, | ||
| animationIteration: { | ||
| 'infinite': 'infinite', | ||
| 'once': '1', | ||
| 'twice': '2', | ||
| 'thrice': '3', | ||
| 1: '1', | ||
| 2: '2', | ||
| 3: '3', | ||
| }, | ||
| animation: { | ||
| 'spin': '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)', | ||
| 'ping': 'ping var(--tw-animate-duration, 1s) var(--tw-animate-easing, cubic-bezier(0, 0, 0.2, 1)) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, infinite) var(--tw-animate-fill, none)', | ||
| 'pulse': 'pulse var(--tw-animate-duration, 2s) var(--tw-animate-easing, cubic-bezier(0.4, 0, 0.6, 1)) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, infinite) var(--tw-animate-fill, none)', | ||
| 'bounce': 'bounce var(--tw-animate-duration, 1s) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, infinite) var(--tw-animate-fill, none)', | ||
| 'wiggle': 'wiggle 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)', | ||
| 'wiggle-more': 'wiggle-more 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)', | ||
| 'rotate-y': 'rotate-y 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)', | ||
| 'rotate-x': 'rotate-x 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)', | ||
| 'jump': 'jump var(--tw-animate-duration, 500ms) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, 1) var(--tw-animate-fill, both)', | ||
| 'jump-in': 'jump-in var(--tw-animate-duration, 500ms) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, 1) var(--tw-animate-fill, both)', | ||
| 'jump-out': 'jump-out var(--tw-animate-duration, 500ms) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, 1) var(--tw-animate-fill, both)', | ||
| 'shake': 'shake var(--tw-animate-duration, 500ms) var(--tw-animate-easing, ease) var(--tw-animate-delay, 0s) var(--tw-animate-iteration, 1) var(--tw-animate-fill, both)', | ||
| 'fade': '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)', | ||
| 'fade-down': 'fade-down 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)', | ||
| 'fade-up': 'fade-up 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)', | ||
| 'fade-left': 'fade-left 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)', | ||
| 'fade-right': 'fade-right 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)', | ||
| 'flip-up': 'flip-up 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)', | ||
| 'flip-down': 'flip-down 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)', | ||
| }, | ||
| keyframes: { | ||
@@ -152,42 +211,3 @@ 'wiggle': { | ||
| }, | ||
| animation: { | ||
| 'wiggle': 'wiggle 1s both', | ||
| 'wiggle-more': 'wiggle-more 1s both', | ||
| 'rotate-y': 'rotate-y 1s both', | ||
| 'rotate-x': 'rotate-x 1s both', | ||
| 'jump': 'jump .5s both', | ||
| 'jump-in': 'jump-in .5s both', | ||
| 'jump-out': 'jump-out .5s both', | ||
| 'shake': 'shake .5s both', | ||
| 'fade': 'fade 1s both', | ||
| 'fade-down': 'fade-down 1s both', | ||
| 'fade-up': 'fade-up 1s both', | ||
| 'fade-left': 'fade-left 1s both', | ||
| 'fade-right': 'fade-right 1s both', | ||
| 'flip-up': 'flip-up 1s both', | ||
| 'flip-down': 'flip-down 1s both', | ||
| }, | ||
| animationDelay: { | ||
| none: '0ms', | ||
| 0: '0ms', | ||
| 75: '75ms', | ||
| 100: '100ms', | ||
| 150: '150ms', | ||
| 200: '200ms', | ||
| 300: '300ms', | ||
| 500: '500ms', | ||
| 700: '700ms', | ||
| 1000: '1000ms', | ||
| }, | ||
| animationDuration: { | ||
| 75: '75ms', | ||
| 100: '100ms', | ||
| 150: '150ms', | ||
| 200: '200ms', | ||
| 300: '300ms', | ||
| 500: '500ms', | ||
| 700: '700ms', | ||
| 1000: '1000ms', | ||
| }, | ||
| }, | ||
| }; | ||
| } |
| module.exports = ({ matchUtilities, theme }) => matchUtilities({ | ||
| 'animate-delay': value => ({ | ||
| 'animation-delay': value, | ||
| '--tw-animate-delay': value, | ||
| 'animation-delay': 'var(--tw-animate-delay)', | ||
| }), | ||
| }, { | ||
| values: theme('animationDelay'), | ||
| }); | ||
| }) |
| module.exports = ({ addUtilities }) => addUtilities({ | ||
| '.animate-normal': { | ||
| 'animation-direction': 'normal', | ||
| '--tw-animate-direction': 'normal', | ||
| 'animation-direction': 'var(--tw-animate-direction)', | ||
| }, | ||
| '.animate-reverse': { | ||
| 'animation-direction': 'reverse', | ||
| '--tw-animate-direction': 'reverse', | ||
| 'animation-direction': 'var(--tw-animate-direction)', | ||
| }, | ||
| '.animate-alternate': { | ||
| 'animation-direction': 'alternate', | ||
| '--tw-animate-direction': 'alternate', | ||
| 'animation-direction': 'var(--tw-animate-direction)', | ||
| }, | ||
| '.animate-alternate-reverse': { | ||
| 'animation-direction': 'alternate-reverse', | ||
| '--tw-animate-direction': 'alternate-reverse', | ||
| 'animation-direction': 'var(--tw-animate-direction)', | ||
| }, | ||
| }); | ||
| }) |
| module.exports = ({ matchUtilities, theme }) => matchUtilities({ | ||
| 'animate-duration': value => ({ | ||
| 'animation-duration': value, | ||
| '--tw-animate-duration': value, | ||
| 'animation-duration': 'var(--tw-animate-duration)', | ||
| }), | ||
| }, { | ||
| values: theme('animationDuration'), | ||
| }); | ||
| }) |
| module.exports = ({ addUtilities }) => addUtilities({ | ||
| '.animate-fill-none': { | ||
| 'animation-fill-mode': 'normal', | ||
| '--tw-animate-fill': 'normal', | ||
| 'animation-fill-mode': 'var(--tw-animate-fill)', | ||
| }, | ||
| '.animate-fill-forwards': { | ||
| 'animation-fill-mode': 'forwards', | ||
| '--tw-animate-fill': 'forwards', | ||
| 'animation-fill-mode': 'var(--tw-animate-fill)', | ||
| }, | ||
| '.animate-fill-backwards': { | ||
| 'animation-fill-mode': 'backwards', | ||
| '--tw-animate-fill': 'backwards', | ||
| 'animation-fill-mode': 'var(--tw-animate-fill)', | ||
| }, | ||
| '.animate-fill-both': { | ||
| 'animation-fill-mode': 'both', | ||
| '--tw-animate-fill': 'both', | ||
| 'animation-fill-mode': 'var(--tw-animate-fill)', | ||
| }, | ||
| }); | ||
| }) |
@@ -1,14 +0,29 @@ | ||
| module.exports = ({ addUtilities }) => 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', | ||
| }, | ||
| }); | ||
| module.exports = ({ addUtilities, matchUtilities, theme }) => { | ||
| addUtilities({ | ||
| '.animate-infinite': { | ||
| '--tw-animate-iteration': 'infinite', | ||
| 'animation-iteration-count': 'var(--tw-animate-iteration)', | ||
| }, | ||
| '.animate-once': { | ||
| '--tw-animate-iteration': '1', | ||
| 'animation-iteration-count': 'var(--tw-animate-iteration)', | ||
| }, | ||
| '.animate-twice': { | ||
| '--tw-animate-iteration': '2', | ||
| 'animation-iteration-count': 'var(--tw-animate-iteration)', | ||
| }, | ||
| '.animate-thrice': { | ||
| '--tw-animate-iteration': '3', | ||
| 'animation-iteration-count': 'var(--tw-animate-iteration)', | ||
| }, | ||
| }) | ||
| matchUtilities({ | ||
| 'animate-iteration': value => ({ | ||
| '--tw-animate-iteration': value, | ||
| 'animation-iteration-count': 'var(--tw-animate-iteration)', | ||
| }), | ||
| }, { | ||
| values: theme('animationIteration'), | ||
| }) | ||
| } |
| module.exports = ({ addUtilities }) => addUtilities({ | ||
| '.animate-run': { | ||
| 'animation-play-state': 'running', | ||
| '--tw-animate-state': 'running', | ||
| 'animation-play-state': 'var(--tw-animate-state)', | ||
| }, | ||
| '.animate-play': { | ||
| 'animation-play-state': 'running', | ||
| '--tw-animate-state': 'running', | ||
| 'animation-play-state': 'var(--tw-animate-state)', | ||
| }, | ||
| '.animate-stop': { | ||
| 'animation-play-state': 'paused', | ||
| '--tw-animate-state': 'paused', | ||
| 'animation-play-state': 'var(--tw-animate-state)', | ||
| }, | ||
| '.animate-pause': { | ||
| 'animation-play-state': 'paused', | ||
| '--tw-animate-state': 'paused', | ||
| 'animation-play-state': 'var(--tw-animate-state)', | ||
| }, | ||
| }); | ||
| }) |
@@ -1,14 +0,8 @@ | ||
| module.exports = ({ addUtilities }) => addUtilities({ | ||
| '.animate-ease-linear': { | ||
| 'animation-timing-function': 'linear', | ||
| }, | ||
| '.animate-ease-in': { | ||
| 'animation-timing-function': 'cubic-bezier(0.4, 0, 1, 1)', | ||
| }, | ||
| '.animate-ease-out': { | ||
| 'animation-timing-function': 'cubic-bezier(0, 0, 0.2, 1)', | ||
| }, | ||
| '.animate-ease-in-out': { | ||
| 'animation-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)', | ||
| }, | ||
| }); | ||
| module.exports = ({ matchUtilities, theme }) => matchUtilities({ | ||
| 'animate-ease': value => ({ | ||
| '--tw-animate-easing': value, | ||
| 'animation-timing-function': 'var(--tw-animate-easing)', | ||
| }), | ||
| }, { | ||
| values: theme('animationTimingFunction'), | ||
| }) |
23166
56.34%13
8.33%360
25%217
27.65%6
50%