13 | ```
14 |
15 | Refer [the demo](./animations) to see the available animations in action. You
16 | can play with them [here](https://play.tailwindcss.com/TsNC9Yw9Nc).
17 |
18 | Also refer the official Tailwind CSS documentation on
19 | [using animations with arbitrary values](https://tailwindcss.com/docs/animation#arbitrary-values).
20 | Note that these classes add some default properties and keyframe definitions
21 | too.
22 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yaml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | workflow_dispatch:
7 |
8 | permissions:
9 | contents: read
10 | pages: write
11 | id-token: write
12 |
13 | concurrency:
14 | group: pages
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | build:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v3
22 | with:
23 | fetch-depth: 0
24 | - uses: pnpm/action-setup@v2
25 | - uses: actions/setup-node@v3
26 | with:
27 | node-version: lts/*
28 | cache: pnpm
29 | - uses: actions/configure-pages@v1
30 | - run: pnpm i && pnpm build && pnpm vitepress build docs --base /animated-tailwindcss/
31 | - uses: actions/upload-pages-artifact@v1
32 | with:
33 | path: docs/.vitepress/dist
34 |
35 | deploy:
36 | environment:
37 | name: github-pages
38 | url: ${{ steps.deployment.outputs.page_url }}
39 | runs-on: ubuntu-latest
40 | needs: build
41 | steps:
42 | - id: deployment
43 | uses: actions/deploy-pages@v1
44 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Divyansh Singh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/docs/animation-fill-mode.md:
--------------------------------------------------------------------------------
1 | # Animation Fill Mode
2 |
3 | | Class | Properties ([MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode)) |
4 | | ------------------------ | ---------------------------------------------------------------------------------------- |
5 | | `animate-fill-none` | `animation-fill-mode: none;` |
6 | | `animate-fill-forwards` | `animation-fill-mode: forwards;` |
7 | | `animate-fill-backwards` | `animation-fill-mode: backwards;` |
8 | | `animate-fill-both` | `animation-fill-mode: both;` |
9 |
10 | By default `animation-fill-mode` is set to `both` for all animations in
11 | Animate.css.
12 |
13 | You can use arbitrary values if you need to reference some globals or write the
14 | fill mode for multiple animations:
15 |
16 | ```html
17 |
Foo
18 |
Bar
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/translation-distance.md:
--------------------------------------------------------------------------------
1 | # Translation Distance
2 |
3 | Certain animations support modifying their translation distance using
4 | `--animate-distance` CSS variable. You can set it using the following utilities:
5 |
6 | | Class | Properties |
7 | | --------------------------- | ----------------------------- |
8 | | `animate-distance-[length]` | `--animate-distance: length;` |
9 |
10 | Here `[length]` is one of Tailwind CSS-style
11 | [widths](https://tailwindcss.com/docs/width). You can also use arbitrary values
12 | instead.
13 |
14 | ::: details
15 |
16 | The following classes can be customized by these utilities:
17 |
18 | ```txt
19 | animate-backXY
20 | animate-bounceXY
21 | animate-fadeXYBig
22 | animate-hinge
23 | animate-zoomXY
24 | ```
25 |
26 | where `X` is one of `{In, Out}` and `Y` is one of `{Down, Left, Right, Up}`.
27 |
28 | `animate-distance-{min, max, fit}` are not supported.
29 |
30 | :::
31 |
32 | ## Examples
33 |
34 | ```html
35 |
Foo
36 |
Bar
37 |
Baz
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/animation-duration.md:
--------------------------------------------------------------------------------
1 | # Animation Duration
2 |
3 | | Class | Properties ([MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-duration)) |
4 | | ------------------------- | --------------------------------------------------------------------------------------- |
5 | | `animate-faster` | `animation-duration: 0.5s;` |
6 | | `animate-fast` | `animation-duration: 0.8s;` |
7 | | `animate-slow` | `animation-duration: 2s;` |
8 | | `animate-slower` | `animation-duration: 3s;` |
9 | | `animate-duration-[time]` | `animation-duration: time;` |
10 |
11 | Here `[time]` is one of `{75, 100, 150, 200, 300, 500, 700, 1000}` and is
12 | interpreted like 75ms, 100ms... You can also use arbitrary values instead.
13 |
14 | ## Examples
15 |
16 | ```html
17 |
38 |
39 | ---
40 |
41 | ## Documentation
42 |
43 | [View documentation](https://brc-dd.github.io/animated-tailwindcss/)
44 |
45 | ## Installation
46 |
47 | Please see the [full installation instructions](https://brc-dd.github.io/animated-tailwindcss/installation) for detailed steps and examples.
48 |
49 | ### Quick start with NPM
50 |
51 | In a project where you're using Tailwind CSS **v3**, run this to install this
52 | package:
53 |
54 | ```sh
55 | npm add -D animated-tailwindcss
56 | ```
57 |
58 | Then configure your `tailwind.config.js` to use the animations:
59 |
60 | ```js
61 | const { withAnimations } = require('animated-tailwindcss')
62 |
63 | module.exports = withAnimations({
64 | // your (existing) Tailwind CSS config here
65 | })
66 | ```
67 |
68 | ## Credits
69 |
70 | - [Animate.css](https://github.com/animate-css/animate.css) – for
71 | animation utilities & keyframes – used under
72 | [the MIT license](https://cdn.jsdelivr.net/npm/animate.css@4.1.1/LICENSE).
73 | - [Transform.tools](https://github.com/ritz078/transform) – for converting
74 | Animate.css to JS – used under
75 | [the MIT license](https://github.com/ritz078/transform/blob/master/LICENSE).
76 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installation
3 | ---
4 |
5 | # Getting Started
6 |
7 | In a project where you're using Tailwind CSS **v3**, run this to install this
8 | package:
9 |
10 | ```sh
11 | npm add -D animated-tailwindcss
12 | ```
13 |
14 | Then configure your `tailwind.config.js` to use the animations:
15 |
16 | ```js
17 | const { withAnimations } = require('animated-tailwindcss')
18 |
19 | module.exports = withAnimations({
20 | // your (existing) Tailwind CSS config here
21 | })
22 | ```
23 |
24 | :::details Example
25 |
26 | ```js
27 | const { withAnimations } = require('animated-tailwindcss')
28 |
29 | module.exports = withAnimations({
30 | content: ['./src/**/*.{html,js}'],
31 | theme: { extend: {} },
32 | plugins: [],
33 | })
34 | ```
35 |
36 | :::
37 |
38 | After proper config, you can use the animations of Animate.css the same way as
39 | you use those of Tailwind CSS:
40 |
41 | ```html
42 |
Bouncing Heading
43 | ```
44 |
45 | :::info Notes
46 |
47 | - If you're coming from classical Animate.css, please note that you need to
48 | reference the classes using hyphen instead of underscores (e.g.,
49 | `animate-bounce` instead of `animate__bounce`).
50 |
51 | - The built-in animations (`spin`, `ping`, `pulse`, `bounce`) are prefixed by
52 | `tw`. So, if you want Tailwind CSS' bounce you need to write
53 | `animate-twBounce` instead of `animate-bounce`.
54 |
55 | - The animations this package provides are not exactly same as that of
56 | Animate.css. We have done some modifications to provide you with more
57 | consistent and customizable animations.
58 |
59 | :::
60 |
61 | ## With Play CDN
62 |
63 | It is as simple as this:
64 |
65 | ```html
66 |
67 |
68 |
69 |
70 |
71 | Welcome
72 |
73 | // [!code focus:6]
74 |
75 |
79 |
80 |
81 |
82 |
Hi!
83 |
84 |
85 |
86 | ```
87 |
88 |
103 |
104 | :::warning
105 |
106 | The Play CDN is not suitable for production builds, and the above example will
107 | not work if your browser does not support ES6 modules
108 | (_[Can I use?](https://caniuse.com/es6-module) _).
109 |
110 | :::
111 |
--------------------------------------------------------------------------------
/src/utilities.ts:
--------------------------------------------------------------------------------
1 | import type { CSSBlock } from './types.js'
2 |
3 | export const keyframeUtils: CSSBlock = {
4 | twSpin: { animationTimingFunction: 'linear' },
5 | twPing: { animationTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)' },
6 | twPulse: { animationDuration: '2s', animationTimingFunction: 'cubic-bezier(0.4, 0, 0.6, 1)' },
7 | bounce: { transformOrigin: 'center bottom' },
8 | pulse: { animationTimingFunction: 'ease-in-out' },
9 | headShake: { animationTimingFunction: 'ease-in-out' },
10 | swing: { transformOrigin: 'top center' },
11 | jello: { transformOrigin: 'center' },
12 | heartBeat: { animationDuration: '1.3s', animationTimingFunction: 'ease-in-out' },
13 | bounceIn: {
14 | animationDuration: '0.75s',
15 | animationTimingFunction: 'cubic-bezier(0.215, 0.61, 0.355, 1)',
16 | },
17 | bounceInDown: { animationTimingFunction: 'cubic-bezier(0.215, 0.61, 0.355, 1)' },
18 | bounceInLeft: { animationTimingFunction: 'cubic-bezier(0.215, 0.61, 0.355, 1)' },
19 | bounceInRight: { animationTimingFunction: 'cubic-bezier(0.215, 0.61, 0.355, 1)' },
20 | bounceInUp: { animationTimingFunction: 'cubic-bezier(0.215, 0.61, 0.355, 1)' },
21 | bounceOut: { animationDuration: '0.75s' },
22 | flip: { backfaceVisibility: 'visible' },
23 | flipInX: { backfaceVisibility: 'visible' },
24 | flipInY: { backfaceVisibility: 'visible' },
25 | flipOutX: { animationDuration: '0.75s', backfaceVisibility: 'visible' },
26 | flipOutY: { animationDuration: '0.75s', backfaceVisibility: 'visible' },
27 | lightSpeedInRight: { animationTimingFunction: 'ease-out' },
28 | lightSpeedInLeft: { animationTimingFunction: 'ease-out' },
29 | lightSpeedOutRight: { animationTimingFunction: 'ease-in' },
30 | lightSpeedOutLeft: { animationTimingFunction: 'ease-in' },
31 | rotateIn: { transformOrigin: 'center' },
32 | rotateInDownLeft: { transformOrigin: 'left bottom' },
33 | rotateInDownRight: { transformOrigin: 'right bottom' },
34 | rotateInUpLeft: { transformOrigin: 'left bottom' },
35 | rotateInUpRight: { transformOrigin: 'right bottom' },
36 | rotateOut: { transformOrigin: 'center' },
37 | rotateOutDownLeft: { transformOrigin: 'left bottom' },
38 | rotateOutDownRight: { transformOrigin: 'right bottom' },
39 | rotateOutUpLeft: { transformOrigin: 'left bottom' },
40 | rotateOutUpRight: { transformOrigin: 'right bottom' },
41 | hinge: {
42 | animationDuration: '2s',
43 | animationTimingFunction: 'ease-in-out',
44 | transformOrigin: 'top left',
45 | },
46 | zoomOutDown: { transformOrigin: 'center bottom' },
47 | zoomOutLeft: { transformOrigin: 'left center' },
48 | zoomOutRight: { transformOrigin: 'right center' },
49 | zoomOutUp: { transformOrigin: 'center bottom' },
50 | }
51 |
52 | export const animationUtils: CSSBlock = {
53 | none: { animation: 'none' },
54 |
55 | faster: { animationDuration: '0.5s' },
56 | fast: { animationDuration: '0.8s' },
57 | slow: { animationDuration: '2s' },
58 | slower: { animationDuration: '3s' },
59 |
60 | ease: { animationTimingFunction: 'cubic-bezier(.25,.1,.25,1)' },
61 |
62 | infinite: { animationIterationCount: 'infinite' },
63 |
64 | normal: { animationDirection: 'normal' },
65 | reverse: { animationDirection: 'reverse' },
66 | alternate: { animationDirection: 'alternate' },
67 | 'alternate-reverse': { animationDirection: 'alternate-reverse' },
68 |
69 | paused: { animationPlayState: 'paused' },
70 | running: { animationPlayState: 'running' },
71 | }
72 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/package.json",
3 | "name": "animated-tailwindcss",
4 | "version": "4.0.0",
5 | "description": "A configuration to use Animate.css with Tailwind CSS",
6 | "keywords": [
7 | "animate.css",
8 | "animatecss",
9 | "animations",
10 | "configuration",
11 | "css",
12 | "jit",
13 | "keyframes",
14 | "plugin",
15 | "tailwind",
16 | "tailwindcss",
17 | "utilities"
18 | ],
19 | "homepage": "https://brc-dd.github.io/animated-tailwindcss",
20 | "bugs": {
21 | "url": "https://github.com/brc-dd/animated-tailwindcss",
22 | "email": "brc-dd@hotmail.com"
23 | },
24 | "repository": "github:brc-dd/animated-tailwindcss",
25 | "funding": "https://github.com/sponsors/brc-dd",
26 | "license": "MIT",
27 | "author": "Divyansh Singh (https://github.com/brc-dd)",
28 | "sideEffects": false,
29 | "exports": {
30 | ".": {
31 | "types": "./dist/index.d.ts",
32 | "require": "./dist/index.js",
33 | "import": "./dist/index.mjs"
34 | }
35 | },
36 | "main": "dist/index.js",
37 | "module": "dist/index.mjs",
38 | "browser": "dist/index.mjs",
39 | "types": "dist/index.d.ts",
40 | "files": [
41 | "dist/*"
42 | ],
43 | "scripts": {
44 | "build": "rimraf dist && tsup ./src/index.ts --dts-resolve --format esm,cjs --minify --treeshake",
45 | "lint": "lefthook run pre-commit",
46 | "prerelease": "git add . && pnpm i && pnpm build && pnpm lint",
47 | "release": "pnpm prerelease && release-it"
48 | },
49 | "devDependencies": {
50 | "@commitlint/cli": "^17.3.0",
51 | "@commitlint/config-conventional": "^17.3.0",
52 | "@release-it/conventional-changelog": "^5.1.1",
53 | "@tsconfig/node12": "^1.0.11",
54 | "@typescript-eslint/eslint-plugin": "^5.48.0",
55 | "@typescript-eslint/parser": "^5.48.0",
56 | "@vue/tsconfig": "^0.1.3",
57 | "autoprefixer": "^10.4.13",
58 | "csstype": "^3.1.1",
59 | "eslint": "^8.31.0",
60 | "eslint-config-airbnb-base": "^15.0.0",
61 | "eslint-config-airbnb-typescript": "^17.0.0",
62 | "eslint-config-prettier": "^8.6.0",
63 | "eslint-import-resolver-node": "^0.3.6",
64 | "eslint-import-resolver-typescript": "^3.5.2",
65 | "eslint-plugin-eslint-comments": "^3.2.0",
66 | "eslint-plugin-import": "^2.26.0",
67 | "eslint-plugin-prettier": "^4.2.1",
68 | "eslint-plugin-security": "^1.5.0",
69 | "lefthook": "^1.2.6",
70 | "postcss": "^8.4.20",
71 | "prettier": "^2.8.1",
72 | "prettier-plugin-packagejson": "^2.3.0",
73 | "prettier-plugin-tailwindcss": "^0.2.1",
74 | "release-it": "^15.6.0",
75 | "replace": "^1.2.2",
76 | "rimraf": "^3.0.2",
77 | "tailwindcss": "^3.2.4",
78 | "tsup": "^6.5.0",
79 | "typescript": "~4.9.4",
80 | "vitepress": "1.0.0-alpha.35",
81 | "vue": "^3.2.45"
82 | },
83 | "peerDependencies": {
84 | "postcss": "^8",
85 | "tailwindcss": "^3"
86 | },
87 | "peerDependenciesMeta": {
88 | "postcss": {
89 | "optional": true
90 | }
91 | },
92 | "packageManager": "pnpm@7.21.0",
93 | "publishConfig": {
94 | "registry": "https://registry.npmjs.org"
95 | },
96 | "pnpm": {
97 | "peerDependencyRules": {
98 | "ignoreMissing": [
99 | "@algolia/client-search"
100 | ]
101 | },
102 | "patchedDependencies": {
103 | "prettier@2.8.1": "patches/prettier@2.8.1.patch"
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint no-param-reassign: "off" */
2 |
3 | import { delay, distance, duration, ease, fill, repeat } from './defaults.js'
4 | import { keyframes } from './keyframes.js'
5 | import type { CSSBlock, CSSProperties, EntryPoint, KeyValuePair, PluginsConfig } from './types.js'
6 | import { animationUtils, keyframeUtils } from './utilities.js'
7 |
8 | export * from './types.js'
9 |
10 | export const withAnimations: EntryPoint = (config = {}) => {
11 | config.theme = config.theme ?? {}
12 |
13 | // animations
14 | const animations: KeyValuePair = Object.fromEntries(
15 | Object.keys(keyframes).map((k) => [
16 | k,
17 | `${keyframeUtils[k]?.animationDuration ?? '1s'}
18 | ${keyframeUtils[k]?.animationTimingFunction ?? ''}
19 | both ${k}`.replace(/\s+/g, ' '),
20 | ]),
21 | )
22 |
23 | const configAnimations = config.theme.extend?.animation ?? {}
24 | config.theme.animation = { ...animations, ...configAnimations }
25 | delete config.theme.extend?.animation
26 |
27 | // patches
28 | Object.keys(animations).forEach((key) => {
29 | if (key.includes('In')) {
30 | if (!key.includes('slide'))
31 | ((keyframes[key] = keyframes[key] ?? {}).from = keyframes[key]?.from ?? {}).opacity = 0
32 | }
33 |
34 | if (key.includes('Out')) {
35 | if (!key.includes('slide'))
36 | ((keyframes[key] = keyframes[key] ?? {}).to = keyframes[key]?.to ?? {}).opacity = 0
37 | ;((keyframes[key] = keyframes[key] ?? {}).to = keyframes[key]?.to ?? {}).visibility = 'hidden'
38 | }
39 | })
40 |
41 | // keyframes
42 | const configKeyframes = config.theme.extend?.keyframes ?? {}
43 | config.theme.keyframes = { ...keyframes, ...configKeyframes }
44 | delete config.theme.extend?.keyframes
45 |
46 | // utilities
47 | const prefixed: CSSBlock = Object.fromEntries(
48 | Object.entries({ ...keyframeUtils, ...animationUtils }).flatMap(([util, block]) => {
49 | if (util in configAnimations || !block) return []
50 |
51 | const filtered: CSSProperties =
52 | util in animationUtils
53 | ? block // skip filtering
54 | : Object.fromEntries(
55 | Object.entries(block).filter(([key]) => !key.startsWith('animation')),
56 | )
57 |
58 | return Object.keys(filtered).length > 0 ? [[`.animate-${util}`, filtered]] : []
59 | }),
60 | )
61 |
62 | // plugins
63 | const plugins: PluginsConfig = [
64 | // static utilities
65 | ({ addUtilities }): void => {
66 | addUtilities(prefixed)
67 | },
68 |
69 | // dynamic utilities
70 | ({ matchUtilities }): void => {
71 | matchUtilities(
72 | { 'animate-duration': (value) => ({ animationDuration: value }) },
73 | { values: duration },
74 | )
75 |
76 | matchUtilities(
77 | { 'animate-ease': (value) => ({ animationTimingFunction: `cubic-bezier(${value})` }) },
78 | { values: ease },
79 | )
80 |
81 | matchUtilities(
82 | {
83 | 'animate-steps-start': (value) => ({
84 | animationTimingFunction: `steps(${value},jump-start)`,
85 | }),
86 | },
87 | { values: repeat },
88 | )
89 |
90 | matchUtilities(
91 | {
92 | 'animate-steps-end': (value) => ({ animationTimingFunction: `steps(${value},jump-end)` }),
93 | },
94 | { values: repeat },
95 | )
96 |
97 | matchUtilities(
98 | {
99 | 'animate-steps-both': (value) => ({
100 | animationTimingFunction: `steps(${value},jump-both)`,
101 | }),
102 | },
103 | { values: repeat },
104 | )
105 |
106 | matchUtilities(
107 | {
108 | 'animate-steps-none': (value) => ({
109 | animationTimingFunction: `steps(${value},jump-none)`,
110 | }),
111 | },
112 | { values: repeat },
113 | )
114 |
115 | matchUtilities({ 'animate-delay': (value) => ({ animationDelay: value }) }, { values: delay })
116 |
117 | matchUtilities(
118 | { 'animate-repeat': (value) => ({ animationIterationCount: value }) },
119 | { values: repeat },
120 | )
121 |
122 | matchUtilities(
123 | { 'animate-fill': (value) => ({ animationFillMode: value }) },
124 | { values: fill },
125 | )
126 |
127 | matchUtilities(
128 | { 'animate-distance': (value) => ({ '--animate-distance': value }) },
129 | { values: distance },
130 | )
131 | },
132 | ]
133 |
134 | const configPlugins = config.plugins ?? []
135 | config.plugins = [...plugins, ...configPlugins]
136 |
137 | return config
138 | }
139 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the overall
26 | community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or advances of
31 | any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email address,
35 | without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | brc-dd@hotmail.com. All complaints will be reviewed and investigated promptly
64 | and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series of
86 | actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or permanent
93 | ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within the
113 | community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by
122 | [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/.eslintrc.yaml:
--------------------------------------------------------------------------------
1 | root: true
2 | env:
3 | node: true
4 | extends:
5 | - plugin:eslint-comments/recommended
6 | - plugin:import/recommended
7 | - plugin:import/typescript
8 | - plugin:security/recommended
9 | - eslint:recommended
10 | - plugin:@typescript-eslint/recommended
11 | - plugin:@typescript-eslint/recommended-requiring-type-checking
12 | - airbnb-base
13 | - airbnb-typescript/base
14 | - plugin:prettier/recommended
15 | ignorePatterns:
16 | - dist
17 | - '!.vitepress'
18 | parser: '@typescript-eslint/parser'
19 | parserOptions:
20 | ecmaVersion: 2019
21 | project:
22 | - tsconfig.json
23 | - docs/tsconfig.json
24 | sourceType: module
25 | plugins:
26 | - '@typescript-eslint'
27 | - security
28 | settings:
29 | import/resolver:
30 | typescript:
31 | alwaysTryTypes: true
32 | project: .
33 | rules:
34 | eslint-comments/no-unused-disable: error
35 | security/detect-object-injection: off # ts handles this
36 | import/no-extraneous-dependencies:
37 | - error
38 | - devDependencies: true
39 | import/prefer-default-export: off
40 | '@typescript-eslint/array-type':
41 | - error
42 | - default: generic
43 | '@typescript-eslint/ban-tslint-comment': error
44 | '@typescript-eslint/class-literal-property-style': error
45 | '@typescript-eslint/consistent-indexed-object-style': error
46 | '@typescript-eslint/consistent-type-assertions': error
47 | '@typescript-eslint/consistent-type-definitions':
48 | - error
49 | - type
50 | '@typescript-eslint/consistent-type-exports': error
51 | '@typescript-eslint/consistent-type-imports':
52 | - error
53 | - disallowTypeAnnotations: false
54 | '@typescript-eslint/explicit-function-return-type': error
55 | '@typescript-eslint/explicit-member-accessibility': error
56 | '@typescript-eslint/explicit-module-boundary-types': error
57 | '@typescript-eslint/member-ordering': error
58 | '@typescript-eslint/method-signature-style': error
59 | '@typescript-eslint/naming-convention': error
60 | '@typescript-eslint/no-base-to-string': error
61 | '@typescript-eslint/no-confusing-non-null-assertion': error
62 | '@typescript-eslint/no-confusing-void-expression': error
63 | '@typescript-eslint/no-dynamic-delete': error
64 | '@typescript-eslint/no-extraneous-class': error
65 | '@typescript-eslint/no-invalid-void-type': error
66 | '@typescript-eslint/no-meaningless-void-operator': error
67 | '@typescript-eslint/no-non-null-asserted-nullish-coalescing': error
68 | '@typescript-eslint/no-parameter-properties': error
69 | '@typescript-eslint/no-require-imports': error
70 | '@typescript-eslint/no-unnecessary-boolean-literal-compare': error
71 | '@typescript-eslint/no-unnecessary-condition': error
72 | '@typescript-eslint/no-unnecessary-qualifier': error
73 | '@typescript-eslint/no-unnecessary-type-arguments': error
74 | '@typescript-eslint/non-nullable-type-assertion-style': error
75 | '@typescript-eslint/prefer-enum-initializers': error
76 | '@typescript-eslint/prefer-for-of': error
77 | '@typescript-eslint/prefer-function-type': error
78 | '@typescript-eslint/prefer-includes': error
79 | '@typescript-eslint/prefer-literal-enum-member': error
80 | '@typescript-eslint/prefer-nullish-coalescing': error
81 | '@typescript-eslint/prefer-optional-chain': error
82 | '@typescript-eslint/prefer-readonly': error
83 | '@typescript-eslint/prefer-reduce-type-parameter': error
84 | '@typescript-eslint/prefer-regexp-exec': error
85 | '@typescript-eslint/prefer-return-this-type': error
86 | '@typescript-eslint/prefer-string-starts-ends-with': error
87 | '@typescript-eslint/prefer-ts-expect-error': error
88 | '@typescript-eslint/promise-function-async': error
89 | '@typescript-eslint/require-array-sort-compare':
90 | - error
91 | - ignoreStringArrays: true
92 | '@typescript-eslint/sort-type-union-intersection-members': error
93 | '@typescript-eslint/strict-boolean-expressions': error
94 | '@typescript-eslint/switch-exhaustiveness-check': error
95 | '@typescript-eslint/type-annotation-spacing': error
96 | '@typescript-eslint/typedef': error
97 | '@typescript-eslint/unified-signatures': error
98 |
99 | # Override/Extension Rules
100 | brace-style: off
101 | '@typescript-eslint/brace-style': error
102 | comma-dangle: off
103 | '@typescript-eslint/comma-dangle': error
104 | comma-spacing: off
105 | '@typescript-eslint/comma-spacing': error
106 | default-param-last: off
107 | '@typescript-eslint/default-param-last': error
108 | dot-notation: off
109 | '@typescript-eslint/dot-notation': error
110 | func-call-spacing: off
111 | '@typescript-eslint/func-call-spacing': error
112 | init-declarations: off
113 | '@typescript-eslint/init-declarations': error
114 | keyword-spacing: off
115 | '@typescript-eslint/keyword-spacing': error
116 | lines-between-class-members: off
117 | '@typescript-eslint/lines-between-class-members': error
118 | no-dupe-class-members: off
119 | '@typescript-eslint/no-dupe-class-members': error
120 | no-duplicate-imports: off
121 | '@typescript-eslint/no-duplicate-imports': error
122 | no-extra-parens: off
123 | '@typescript-eslint/no-extra-parens': error
124 | no-invalid-this: off
125 | '@typescript-eslint/no-invalid-this': error
126 | no-loop-func: off
127 | '@typescript-eslint/no-loop-func': error
128 | no-redeclare: off
129 | '@typescript-eslint/no-redeclare': error
130 | no-restricted-imports: off
131 | '@typescript-eslint/no-restricted-imports': error
132 | no-shadow: off
133 | '@typescript-eslint/no-shadow': error
134 | no-throw-literal: off
135 | '@typescript-eslint/no-throw-literal': error
136 | no-unused-expressions: off
137 | '@typescript-eslint/no-unused-expressions': error
138 | no-use-before-define: off
139 | '@typescript-eslint/no-use-before-define': error
140 | no-useless-constructor: off
141 | '@typescript-eslint/no-useless-constructor': error
142 | object-curly-spacing: off
143 | '@typescript-eslint/object-curly-spacing': error
144 | padding-line-between-statements: off
145 | '@typescript-eslint/padding-line-between-statements': error
146 | quotes: off
147 | '@typescript-eslint/quotes': error
148 | no-return-await: off
149 | '@typescript-eslint/return-await': error
150 | semi: off
151 | space-before-function-paren: off
152 | '@typescript-eslint/space-before-function-paren': error
153 | space-infix-ops: off
154 | '@typescript-eslint/space-infix-ops': error
155 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/tailwindlabs/play.tailwindcss.com/tree/master/src/monaco/ *.d.ts
2 |
3 | import type * as CSS from 'csstype'
4 | import type * as postcss from 'postcss'
5 |
6 | export type KeyValuePair = Record
7 |
8 | export type CSSProperties = CSS.Properties & Record<`--${string}`, string>
9 |
10 | export type CSSBlock = Record
11 |
12 | export type Keyframes = Record
13 |
14 | export type ConfigUtils = {
15 | negative: (input: TInput) => TOutput
16 | breakpoints: (input: TInput) => TOutput
17 | }
18 |
19 | export type ConfigDotNotationPath = string
20 |
21 | export type ResolvableTo =
22 | | TResult
23 | | ((theme: (path: ConfigDotNotationPath) => TResult, utils: ConfigUtils) => TResult)
24 |
25 | export type BaseConfig = {
26 | important: boolean | string
27 | target: 'ie11' | 'relaxed'
28 | prefix: string | ((className: string) => string)
29 | separator: string
30 | }
31 |
32 | export type PurgeConfig =
33 | | Array
34 | | false
35 | | { enabled: boolean; mode: 'all' | 'conservative'; content: Array }
36 | | { enabled: boolean; options: { content: Array; whitelist: Array } }
37 |
38 | export type ContentConfig =
39 | | Array
40 | | {
41 | files: Array
42 | safelist?: Array }>
43 | transform?: Record string>
44 | extract?: Record Array>
45 | }
46 |
47 | export type FutureConfig = Record | 'all' | []
48 |
49 | export type ExperimentalConfig = Record | 'all' | []
50 |
51 | export type DarkModeConfig = 'class' | 'media' | false
52 |
53 | export type BaseThemeConfig = {
54 | extend: Partial>
55 |
56 | /** Responsiveness */
57 | screens: ResolvableTo
58 |
59 | /** Reusable base configs */
60 | colors: ResolvableTo>>
61 | spacing: ResolvableTo
62 |
63 | /** Background */
64 | backgroundColor: BaseThemeConfig['colors']
65 | backgroundImage: ResolvableTo
66 | gradientColorStops: BaseThemeConfig['colors']
67 | backgroundOpacity: BaseThemeConfig['opacity']
68 | backgroundPosition: ResolvableTo
69 | backgroundSize: ResolvableTo
70 | backgroundOrigin: ResolvableTo
71 |
72 | /** Border */
73 | borderColor: BaseThemeConfig['colors']
74 | borderOpacity: BaseThemeConfig['opacity']
75 | borderRadius: ResolvableTo
76 | borderWidth: ResolvableTo
77 |
78 | /** Shadow */
79 | boxShadow: ResolvableTo
80 |
81 | /** Outline */
82 | outline: ResolvableTo
83 |
84 | /** Cursor */
85 | cursor: ResolvableTo
86 |
87 | /** Content */
88 | content: ResolvableTo
89 |
90 | /** Divider */
91 | divideColor: BaseThemeConfig['borderColor']
92 | divideOpacity: BaseThemeConfig['borderOpacity']
93 | devideWidth: BaseThemeConfig['borderWidth']
94 |
95 | /** SVG */
96 | fill: ResolvableTo
97 | stroke: ResolvableTo
98 | strokeWidth: ResolvableTo
99 |
100 | /** Flexbox */
101 | flex: ResolvableTo
102 | flexGrow: ResolvableTo
103 | flexShrink: ResolvableTo
104 |
105 | /** Fonts */
106 | fontFamily: ResolvableTo>>
107 | fontSize: ResolvableTo
108 | fontWeight: ResolvableTo
109 |
110 | /** Sizes */
111 | height: BaseThemeConfig['spacing']
112 | minHeight: ResolvableTo
113 | maxHeight: ResolvableTo
114 | width: BaseThemeConfig['spacing']
115 | minWidth: ResolvableTo
116 | maxWidth: ResolvableTo
117 | aspectRatio: ResolvableTo
118 |
119 | /** Positioning */
120 | inset: ResolvableTo
121 | zIndex: ResolvableTo
122 |
123 | /** Text */
124 | letterSpacing: ResolvableTo
125 | lineHeight: ResolvableTo
126 | textColor: BaseThemeConfig['colors']
127 | textOpacity: BaseThemeConfig['opacity']
128 | textIndent: BaseThemeConfig['spacing']
129 |
130 | /** Input */
131 | placeholderColor: BaseThemeConfig['colors']
132 | placeholderOpacity: BaseThemeConfig['opacity']
133 | caretColor: BaseThemeConfig['colors']
134 |
135 | /** Lists */
136 | listStyleType: ResolvableTo
137 |
138 | /** Layout */
139 | margin: BaseThemeConfig['spacing']
140 | padding: BaseThemeConfig['spacing']
141 | space: BaseThemeConfig['spacing']
142 | opacity: ResolvableTo
143 | order: ResolvableTo
144 | columns: ResolvableTo
145 |
146 | /** Images */
147 | objectPosition: ResolvableTo
148 |
149 | /** Grid */
150 | gap: BaseThemeConfig['spacing']
151 | gridTemplateColumns: ResolvableTo
152 | gridColumn: ResolvableTo
153 | gridColumnStart: ResolvableTo
154 | gridColumnEnd: ResolvableTo
155 | gridTemplateRows: ResolvableTo
156 | gridRow: ResolvableTo
157 | gridRowStart: ResolvableTo
158 | gridRowEnd: ResolvableTo
159 |
160 | /** Transformations */
161 | transformOrigin: ResolvableTo
162 | scale: ResolvableTo
163 | rotate: ResolvableTo
164 | translate: BaseThemeConfig['spacing']
165 | skew: ResolvableTo
166 |
167 | /** Transitions */
168 | transitionProperty: ResolvableTo
169 | transitionTimingFunction: ResolvableTo
170 | transitionDuration: ResolvableTo
171 | transitionDelay: ResolvableTo
172 | willChange: ResolvableTo
173 |
174 | /** Animations */
175 | animation: ResolvableTo
176 | keyframes: ResolvableTo
177 |
178 | /** Filters */
179 | blur: ResolvableTo | string>>
180 | brightness: ResolvableTo | string>>
181 | contrast: ResolvableTo | string>>
182 | dropShadow: ResolvableTo | string>>
183 | grayscale: ResolvableTo | string>>
184 | hueRotate: ResolvableTo | string>>
185 | invert: ResolvableTo | string>>
186 | saturate: ResolvableTo | string>>
187 | sepia: ResolvableTo | string>>
188 | backdropFilter: ResolvableTo | string>>
189 | backdropBlur: ResolvableTo | string>>
190 | backdropBrightness: ResolvableTo | string>>
191 | backdropContrast: ResolvableTo | string>>
192 | backdropGrayscale: ResolvableTo | string>>
193 | backdropHueRotate: ResolvableTo | string>>
194 | backdropInvert: ResolvableTo | string>>
195 | backdropOpacity: ResolvableTo | string>>
196 | backdropSaturate: ResolvableTo | string>>
197 | backdropSepia: ResolvableTo | string>>
198 |
199 | /** Components */
200 | container: Partial<{
201 | screens: Array | Record | Record
202 | center: boolean
203 | padding: KeyValuePair | string
204 | }>
205 | }
206 |
207 | export type ThemeConfig = Partial>
208 |
209 | export type VariantsAPI = {
210 | variants: (path: string) => Array
211 |
212 | before: (
213 | toInsert: Array,
214 | variant?: string,
215 | existingPluginVariants?: Array,
216 | ) => Array
217 |
218 | after: (
219 | toInsert: Array,
220 | variant?: string,
221 | existingPluginVariants?: Array,
222 | ) => Array
223 |
224 | without: (toRemove: Array, existingPluginVariants?: Array) => Array
225 | }
226 |
227 | export type VariantsConfig =
228 | | Array
229 | | Record | ((api: VariantsAPI) => Array)>
230 | | { extend: Record> }
231 |
232 | export type CorePluginsConfig = Array | Record
233 |
234 | export type VariantConfig =
235 | | Array
236 | | Partial<{ variants: Array; respectPrefix: false; respectImportant: false }>
237 |
238 | export type ValueType =
239 | | 'absolute-size'
240 | | 'any'
241 | | 'color'
242 | | 'family-name'
243 | | 'generic-name'
244 | | 'image'
245 | | 'length'
246 | | 'line-width'
247 | | 'lookup'
248 | | 'number'
249 | | 'percentage'
250 | | 'position'
251 | | 'relative-size'
252 | | 'url'
253 |
254 | export type PluginAPI = {
255 | /** Get access to the whole config */
256 | config: (
257 | path?: ConfigDotNotationPath,
258 | defaultValue?: TDefaultValue,
259 | ) => TDefaultValue
260 |
261 | /** Escape classNames */
262 | e: (className: string) => string
263 |
264 | /** Shortcut for the theme section of the config */
265 | theme: (path: ConfigDotNotationPath, defaultValue?: TDefaultValue) => TDefaultValue
266 |
267 | variants: (
268 | path: ConfigDotNotationPath,
269 | defaultValue: TDefaultValue,
270 | ) => TDefaultValue
271 |
272 | target: (path: ConfigDotNotationPath) => string
273 |
274 | prefix: (selector: string) => string
275 |
276 | /** Ability to add utilities. E.g.: .p-4 */
277 | addUtilities: (utilities: CSSBlock, variantConfig?: VariantConfig) => void
278 |
279 | /** Ability to add components. E.g.: .btn */
280 | addComponents: (components: CSSBlock, variantConfig?: VariantConfig) => void
281 |
282 | addBase: (base: CSSBlock) => void
283 |
284 | addVariant: (
285 | name: string,
286 | generator: (api: {
287 | container: postcss.Container
288 | separator: string
289 | modifySelectors: (
290 | modifierFunction: (api: { className: string; selector: string }) => void,
291 | ) => void
292 | }) => void,
293 | ) => void
294 |
295 | matchUtilities: (
296 | utilities: Record CSSProperties>,
297 | options?: Partial<{
298 | values: Record
299 | type: Array | ValueType
300 | respectPrefix: boolean
301 | respectImportant: boolean
302 | respectVariants: boolean
303 | }>,
304 | ) => void
305 |
306 | corePlugins: (path: string) => boolean
307 |
308 | postcss: typeof postcss
309 | }
310 |
311 | export type PluginCreator = (api: PluginAPI) => void
312 |
313 | export type PluginsConfig = Array<
314 | PluginCreator | { handler: PluginCreator; config?: TailwindConfig }
315 | >
316 |
317 | /** The holy grail Tailwind config definition */
318 | export type TailwindConfig = Partial<
319 | BaseConfig &
320 | Record & {
321 | presets: Array
322 | future: FutureConfig
323 | experimental: ExperimentalConfig
324 | purge: PurgeConfig
325 | content: ContentConfig
326 | darkMode: DarkModeConfig
327 | theme: ThemeConfig
328 | variants: VariantsConfig
329 | corePlugins: CorePluginsConfig
330 | plugins: PluginsConfig
331 | mode: 'aot' | 'jit'
332 | }
333 | >
334 |
335 | export type EntryPoint = (config: TailwindConfig) => TailwindConfig
336 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/Demo.vue:
--------------------------------------------------------------------------------
1 |
2 |