diff options
Diffstat (limited to 'node_modules/tailwindcss/src/postcss-plugins/nesting')
3 files changed, 135 insertions, 0 deletions
diff --git a/node_modules/tailwindcss/src/postcss-plugins/nesting/README.md b/node_modules/tailwindcss/src/postcss-plugins/nesting/README.md new file mode 100644 index 0000000..49cdbb5 --- /dev/null +++ b/node_modules/tailwindcss/src/postcss-plugins/nesting/README.md @@ -0,0 +1,42 @@ +# tailwindcss/nesting + +This is a PostCSS plugin that wraps [postcss-nested](https://github.com/postcss/postcss-nested) or [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) and acts as a compatibility layer to make sure your nesting plugin of choice properly understands Tailwind's custom syntax like `@apply` and `@screen`. + +Add it to your PostCSS configuration, somewhere before Tailwind itself: + +```js +// postcss.config.js +module.exports = { + plugins: [ + require('postcss-import'), + require('tailwindcss/nesting'), + require('tailwindcss'), + require('autoprefixer'), + ] +} +``` + +By default, it uses the [postcss-nested](https://github.com/postcss/postcss-nested) plugin under the hood, which uses a Sass-like syntax and is the plugin that powers nesting support in the [Tailwind CSS plugin API](https://tailwindcss.com/docs/plugins#css-in-js-syntax). + +If you'd rather use [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) (which is based on the work-in-progress [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) specification), first install the plugin alongside: + +```shell +npm install postcss-nesting +``` + +Then pass the plugin itself as an argument to `tailwindcss/nesting` in your PostCSS configuration: + +```js +// postcss.config.js +module.exports = { + plugins: [ + require('postcss-import'), + require('tailwindcss/nesting')(require('postcss-nesting')), + require('tailwindcss'), + require('autoprefixer'), + ] +} +``` + +This can also be helpful if for whatever reason you need to use a very specific version of `postcss-nested` and want to override the version we bundle with `tailwindcss/nesting` itself. + diff --git a/node_modules/tailwindcss/src/postcss-plugins/nesting/index.js b/node_modules/tailwindcss/src/postcss-plugins/nesting/index.js new file mode 100644 index 0000000..9fbcddf --- /dev/null +++ b/node_modules/tailwindcss/src/postcss-plugins/nesting/index.js @@ -0,0 +1,13 @@ +import { nesting } from './plugin' + +export default Object.assign( + function (opts) { + return { + postcssPlugin: 'tailwindcss/nesting', + Once(root, { result }) { + return nesting(opts)(root, result) + }, + } + }, + { postcss: true } +) diff --git a/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js b/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js new file mode 100644 index 0000000..a13cfd4 --- /dev/null +++ b/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js @@ -0,0 +1,80 @@ +import postcss from 'postcss' +import postcssNested from 'postcss-nested' + +export function nesting(opts = postcssNested) { + return (root, result) => { + root.walkAtRules('screen', (rule) => { + rule.name = 'media' + rule.params = `screen(${rule.params})` + }) + + root.walkAtRules('apply', (rule) => { + rule.before(postcss.decl({ prop: '__apply', value: rule.params, source: rule.source })) + rule.remove() + }) + + let plugin = (() => { + if ( + typeof opts === 'function' || + (typeof opts === 'object' && opts?.hasOwnProperty?.('postcssPlugin')) + ) { + return opts + } + + if (typeof opts === 'string') { + return require(opts) + } + + if (Object.keys(opts).length <= 0) { + return postcssNested + } + + throw new Error('tailwindcss/nesting should be loaded with a nesting plugin.') + })() + + postcss([plugin]).process(root, result.opts).sync() + + root.walkDecls('__apply', (decl) => { + decl.before(postcss.atRule({ name: 'apply', params: decl.value, source: decl.source })) + decl.remove() + }) + + /** + * Use a private PostCSS API to remove the "clean" flag from the entire AST. + * This is done because running process() on the AST will set the "clean" + * flag on all nodes, which we don't want. + * + * This causes downstream plugins using the visitor API to be skipped. + * + * This is guarded because the PostCSS API is not public + * and may change in future versions of PostCSS. + * + * See https://github.com/postcss/postcss/issues/1712 for more details + * + * @param {import('postcss').Node} node + */ + function markDirty(node) { + if (!('markDirty' in node)) { + return + } + + // Traverse the tree down to the leaf nodes + if (node.nodes) { + node.nodes.forEach((n) => markDirty(n)) + } + + // If it's a leaf node mark it as dirty + // We do this here because marking a node as dirty + // will walk up the tree and mark all parents as dirty + // resulting in a lot of unnecessary work if we did this + // for every single node + if (!node.nodes) { + node.markDirty() + } + } + + markDirty(root) + + return root + } +} |