tailwindcss-pseudo-elements
Advanced tools
Comparing version
@@ -1,2 +0,7 @@ | ||
const addContentUtilities = ({ addUtilities, prefix, pseudoClasses }) => { | ||
const addContentUtilities = ({ | ||
addUtilities, | ||
namer, | ||
prefix, | ||
pseudoClasses, | ||
}) => { | ||
const targetPseudoElements = ['before', 'after'] | ||
@@ -6,3 +11,3 @@ const utilities = targetPseudoElements.reduce((icurrent, pseudoElement) => { | ||
...icurrent, | ||
[`.content-${pseudoElement}::${pseudoElement}`]: { | ||
[`.${namer(`content-${pseudoElement}`)}::${pseudoElement}`]: { | ||
content: `attr(${prefix}-${pseudoElement})`, | ||
@@ -13,3 +18,5 @@ }, | ||
...jcurrent, | ||
[`.content-${pseudoClass}-${pseudoElement}:${pseudoClass}::${pseudoElement}`]: { | ||
[`.${namer( | ||
`content-${pseudoClass}-${pseudoElement}` | ||
)}:${pseudoClass}::${pseudoElement}`]: { | ||
content: `attr(${prefix}-${pseudoClass}-${pseudoElement})`, | ||
@@ -16,0 +23,0 @@ }, |
154
index.js
@@ -0,55 +1,145 @@ | ||
const tailwindcssPlugin = require('tailwindcss/plugin') | ||
const addContentUtilities = require('./content-utilities') | ||
const { pseudoElements, pseudoClasses, hasPluginFactory } = require('./lib') | ||
const { pseudoElements, pseudoClasses } = require('./lib') | ||
const plugin = ({ addUtilities, addVariant, e, config }) => { | ||
const escape = hasPluginFactory ? e : (x) => x | ||
const customPseudoElements = config | ||
? config('customPseudoElements') || [] | ||
: [] | ||
const customPseudoClasses = config ? config('customPseudoClasses') || [] : [] | ||
const defaultOptions = { | ||
customPseudoElements: [], | ||
customPseudoClasses: [], | ||
contentUtilities: { | ||
prefix: 'tw-content', | ||
}, | ||
classNameReplacer: {}, | ||
emptyContent: true, | ||
multiplePseudoClasses: [], | ||
} | ||
if (!Array.isArray(customPseudoElements)) { | ||
const plugin = tailwindcssPlugin.withOptions((options = defaultOptions) => { | ||
const pluginConfig = { | ||
...defaultOptions, | ||
...options, | ||
} | ||
if (!Array.isArray(pluginConfig.customPseudoElements)) { | ||
throw new Error('`customElements` must be an array of string.') | ||
} | ||
if (!Array.isArray(customPseudoClasses)) { | ||
if (!Array.isArray(pluginConfig.customPseudoClasses)) { | ||
throw new Error('`customClasses` must be an array of string.') | ||
} | ||
if ( | ||
pluginConfig.contentUtilities !== false && | ||
typeof pluginConfig.contentUtilities !== 'object' | ||
) { | ||
pluginConfig.contentUtilities = defaultOptions.contentUtilities | ||
} | ||
if ( | ||
typeof pluginConfig.classNameReplacer !== 'object' || | ||
Array.isArray(pluginConfig.classNameReplacer) | ||
) { | ||
throw new Error('`classNameReplacer` must be an object.') | ||
} | ||
pluginConfig.multiplePseudoClasses = pluginConfig.multiplePseudoClasses.map( | ||
(s) => s.split(':').slice(1) | ||
) | ||
const namer = (name) => { | ||
return typeof pluginConfig.classNameReplacer === 'object' && | ||
name in pluginConfig.classNameReplacer && | ||
pluginConfig.classNameReplacer[name] | ||
? pluginConfig.classNameReplacer[name] | ||
: name | ||
} | ||
const mergedPseudoElements = Array.from( | ||
new Set(pseudoElements.concat(customPseudoElements)) | ||
new Set(pseudoElements.concat(pluginConfig.customPseudoElements)) | ||
) | ||
const mergedPseudoClasses = Array.from( | ||
new Set(pseudoClasses.concat(customPseudoClasses)) | ||
new Set(pseudoClasses.concat(pluginConfig.customPseudoClasses)) | ||
) | ||
mergedPseudoElements.forEach((pelement) => { | ||
addVariant(pelement, ({ modifySelectors, separator }) => { | ||
modifySelectors(({ className }) => { | ||
return `.${escape(`${pelement}${separator}${className}`)}::${pelement}` | ||
return ({ addUtilities, addVariant, e }) => { | ||
mergedPseudoElements.forEach((pelement) => { | ||
addVariant(pelement, ({ modifySelectors, separator }) => { | ||
modifySelectors(({ className }) => { | ||
return `.${e( | ||
namer(`${pelement}${separator}${className}`) | ||
)}::${pelement}` | ||
}) | ||
}) | ||
}) | ||
}) | ||
mergedPseudoClasses.forEach((pclass) => { | ||
mergedPseudoElements.forEach((pelement) => { | ||
addVariant(`${pclass}_${pelement}`, ({ modifySelectors, separator }) => { | ||
mergedPseudoClasses.forEach((pclass) => { | ||
mergedPseudoElements.forEach((pelement) => { | ||
addVariant( | ||
`${pclass}::${pelement}`, | ||
({ modifySelectors, separator }) => { | ||
modifySelectors(({ className }) => { | ||
return `.${e( | ||
namer( | ||
`${pclass}${separator}${pelement}${separator}${className}` | ||
) | ||
)}:${pclass}::${pelement}` | ||
}) | ||
} | ||
) | ||
}) | ||
}) | ||
pluginConfig.multiplePseudoClasses.forEach((pclassList) => { | ||
const selector = pclassList.join(':') | ||
addVariant(selector, ({ modifySelectors, separator }) => { | ||
modifySelectors(({ className }) => { | ||
return `.${escape( | ||
`${pclass}${separator}${pelement}${separator}${className}` | ||
)}:${pclass}::${pelement}` | ||
return `.${e( | ||
namer(`${pclassList.join(separator)}${separator}${className}`) | ||
)}:${selector}` | ||
}) | ||
}) | ||
mergedPseudoElements.forEach((pelement) => { | ||
addVariant( | ||
`${selector}::${pelement}`, | ||
({ modifySelectors, separator }) => { | ||
modifySelectors(({ className }) => { | ||
return `.${e( | ||
namer( | ||
`${pclassList.join( | ||
separator | ||
)}${separator}${pelement}${separator}${className}` | ||
) | ||
)}:${selector}::${pelement}` | ||
}) | ||
} | ||
) | ||
}) | ||
}) | ||
}) | ||
addContentUtilities({ | ||
addUtilities, | ||
prefix: 'tw-content', | ||
pseudoClasses: mergedPseudoClasses, | ||
}) | ||
} | ||
if (pluginConfig.contentUtilities) { | ||
addContentUtilities({ | ||
addUtilities, | ||
namer, | ||
prefix: | ||
'prefix' in pluginConfig.contentUtilities | ||
? pluginConfig.contentUtilities.prefix | ||
: defaultOptions.contentUtilities.prefix, | ||
pseudoClasses: mergedPseudoClasses, | ||
}) | ||
} | ||
module.exports = hasPluginFactory | ||
? require('tailwindcss/plugin')(plugin) | ||
: plugin | ||
if (pluginConfig.emptyContent) { | ||
addUtilities( | ||
{ | ||
[`.${namer('empty-content')}`]: { | ||
content: "''", | ||
}, | ||
}, | ||
['before'] | ||
) | ||
} | ||
} | ||
}) | ||
module.exports = plugin |
11
lib.js
@@ -17,2 +17,3 @@ /* DON'T EDIT THIS FILE. This is generated by 'scripts/update-pseudos.js' */ | ||
'spelling-error', | ||
'target-text', | ||
], | ||
@@ -23,2 +24,3 @@ | ||
'any-link', | ||
'autofill', | ||
'blank', | ||
@@ -71,11 +73,2 @@ 'checked', | ||
], | ||
hasPluginFactory: (() => { | ||
try { | ||
require.resolve('tailwindcss/plugin') | ||
} catch (e) { | ||
return false | ||
} | ||
return true | ||
})(), | ||
} |
{ | ||
"name": "tailwindcss-pseudo-elements", | ||
"version": "1.5.1", | ||
"version": "2.0.0", | ||
"description": "TailwindCSS Plugin that adds variants of pseudo elements.", | ||
@@ -25,3 +25,3 @@ "main": "index.js", | ||
"lint:eslint": "eslint .", | ||
"lint:prettier": "prettier .", | ||
"lint:prettier": "prettier --check .", | ||
"pretest": "yarn update && yarn lint", | ||
@@ -35,13 +35,13 @@ "update": "node scripts/update-pseudos.js", | ||
"@croutonn/eslint-config": "^1.0.14", | ||
"chai": "^4.2.0", | ||
"chai": "^4.3.4", | ||
"eslint": "^7.15.0", | ||
"mocha": "^8.2.1", | ||
"postcss": "^8.1.14", | ||
"mocha": "^8.3.2", | ||
"postcss": "^8.2.9", | ||
"prettier": "^2.2.1", | ||
"puppeteer": "^5.5.0", | ||
"tailwindcss": "^2.0.1" | ||
"puppeteer": "^8.0.0", | ||
"tailwindcss": "^2.0.4" | ||
}, | ||
"peerDependencies": { | ||
"tailwindcss": ">=0.7.4" | ||
"tailwindcss": ">=1.0.0" | ||
} | ||
} |
153
README.md
@@ -1,7 +0,28 @@ | ||
# tailwindcss-pseudo-elements | ||
# tailwindcss-pseudo-elements <!-- omit in toc --> | ||
TailwindCSS Plugin that adds variants of pseudo elements (`::before`, `::after`, `::first-letter`, etc.). | ||
TailwindCSS Plug-in that adds variants of pseudo elements (`::before`, `::after`, `::first-letter`, etc.). | ||
## Usage | ||
--- | ||
- [Getting Started](#getting-started) | ||
- [Install](#install) | ||
- [NPM](#npm) | ||
- [Yarn](#yarn) | ||
- [Write the configuration for the plug-in](#write-the-configuration-for-the-plug-in) | ||
- [Set the variants](#set-the-variants) | ||
- [Write the HTML](#write-the-html) | ||
- [Content Property Utilities](#content-property-utilities) | ||
- [Empty Property Utility](#empty-property-utility) | ||
- [Options](#options) | ||
- [`customPseudoClasses` and `customPseudoElements`](#custompseudoclasses-and-custompseudoelements) | ||
- [`contentUtilities`](#contentutilities) | ||
- [`emptyContent`](#emptycontent) | ||
- [`classNameReplacer`](#classnamereplacer) | ||
- [Recommended](#recommended) | ||
- [tailwindcss-aspect-ratio](#tailwindcss-aspect-ratio) | ||
--- | ||
## Getting Started | ||
### Install | ||
@@ -21,7 +42,28 @@ | ||
### Configuration | ||
### Write the configuration for the plug-in | ||
Pass [the option](#options) object to the plug-in as follows: | ||
```js | ||
const plugin = require('tailwindcss/plugin') | ||
module.exports = { | ||
plugins: [ | ||
require('tailwindcss-pseudo-elements')({ | ||
customPseudoClasses: ['foo'], | ||
customPseudoElements: ['bar'], | ||
contentUtilities: false, | ||
emptyContent: false, | ||
classNameReplacer: { | ||
'hover:before:text-black': 'hbt', | ||
}, | ||
}), | ||
], | ||
} | ||
``` | ||
### Set the variants | ||
Naming convention of the variants is like `pseudo-class:pseudo-class::pseudo-element`. | ||
An example configuration is shown below. | ||
```js | ||
module.exports = { | ||
@@ -36,43 +78,14 @@ variants: { | ||
'after', | ||
// If you want to combine it with a pseudo class, | ||
// use `<pseudo-class>_<pseudo-element>`. | ||
'hover_before', | ||
'hover_after', | ||
'focus_before', | ||
'foo_bar', | ||
'hover::before', | ||
'hover::after', | ||
'focus::before', | ||
'checked:hover', | ||
'checked:hover::before', | ||
], | ||
}, | ||
}, | ||
// You can set up your own pseudo-classes and pseudo-elements. | ||
customPseudoClasses: ['foo'], | ||
customPseudoElements: ['bar'], | ||
plugins: [ | ||
require('tailwindcss-pseudo-elements'), | ||
// This plugin is useful in combination with tailwindcss-aspect-ratio. | ||
require('tailwindcss-aspect-ratio')({ | ||
ratios: { | ||
'16/9': [16, 9], | ||
'4/3': [4, 3], | ||
'3/2': [3, 2], | ||
'1/1': [1, 1], | ||
}, | ||
variants: ['before', 'hover_before', 'responsive'], | ||
}), | ||
plugin(function ({ addUtilities }) { | ||
addUtilities( | ||
{ | ||
'.empty-content': { | ||
content: "''", | ||
}, | ||
}, | ||
['before'] | ||
) | ||
}), | ||
], | ||
} | ||
``` | ||
### HTML | ||
### Write the HTML | ||
@@ -98,3 +111,3 @@ ```html | ||
<p | ||
class="text-lg text-blue-600 content-before content-after content-hover-before" | ||
class="content-before content-after content-hover-before" | ||
tw-content-before="๐งก" | ||
@@ -107,1 +120,59 @@ tw-content-hover-before="๐" | ||
``` | ||
#### Empty Property Utility | ||
There is a utility class that sets `{ content: "" }` in the `::before`. | ||
```html | ||
<p class="before:empty-content"></p> | ||
``` | ||
## Options | ||
### `customPseudoClasses` and `customPseudoElements` | ||
You can set up your own pseudo-classes and pseudo-elements. | ||
type: `string[]` | ||
default: `[]` | ||
### `contentUtilities` | ||
Configuration of [the Content Property Utilities](#content-property-utilities). | ||
type: `boolean | { "prefix": string }` | ||
default: `{ "prefix": "tw-content" }` | ||
### `emptyContent` | ||
Whether to generate [the Empty Property Utility](#empty-property-utility). | ||
type: `boolean` | ||
default: `true` | ||
### `classNameReplacer` | ||
You can replace frequently used class names with different names. | ||
type: `Record<string, string>` | ||
default: `{}` | ||
## Recommended | ||
### tailwindcss-aspect-ratio | ||
```js | ||
plugins: [ | ||
require('tailwindcss-pseudo-elements')(pseudoOptions), | ||
require('tailwindcss-aspect-ratio')({ | ||
ratios: { | ||
'16/9': [16, 9], | ||
'4/3': [4, 3], | ||
'3/2': [3, 2], | ||
'1/1': [1, 1], | ||
}, | ||
variants: ['before', 'hover::before', 'responsive'], | ||
}), | ||
], | ||
} | ||
``` |
@@ -52,11 +52,2 @@ const fs = require('fs') | ||
], | ||
hasPluginFactory: (() => { | ||
try { | ||
require.resolve('tailwindcss/plugin') | ||
} catch (e) { | ||
return false | ||
} | ||
return true | ||
})(), | ||
} | ||
@@ -63,0 +54,0 @@ ` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
16614
28.4%311
31.22%175
68.27%