-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support creating new variants through plugins (WIP) #505
Conversation
6538166
to
0dcf1a1
Compare
Allows you to write a plugin that registers a new variant but only allows you to modify the selector (like what our built-in generators do.) Next steps are to support variants that wrap rules with at-rules (like @supports for example), variants that can modify properties (as opposed to just selectors), and to give variant plugin authors control over how responsive variants interact with their own variants.
3b377a9
to
f974b8d
Compare
I've pushed some updates to this PR to support variant generators that modify properties as well as variant generators that need to wrap rules in an at-rule. I've done this by giving variant plugins complete control to manipulate the CSS AST using the regular PostCSS API. Note: This replaces the API the PR started with, where you only needed to return a string to change a selector name. Now the For example, here's a plugin that creates a new function({ addVariant }) {
addVariant('important', ({ container }) => {
container.walkRules(rule => {
rule.selector = `.\\!${rule.selector.slice(1)}`
rule.walkDecls(decl => {
decl.important = true
})
})
})
} ...and here's one that adds a function({ addVariant }) {
addVariant('supports-grid', ({ container, separator }) => {
const supportsRule = postcss.atRule({ name: 'supports', params: '(display: grid)' })
supportsRule.nodes = container.nodes
container.nodes = [supportsRule]
supportsRule.walkRules(rule => {
rule.selector = `.supports-grid${separator}${rule.selector.slice(1)}`
})
})
} I'd like to provide some more ergonomic abstractions on top of the raw PostCSS API for common situations, but this feels like the right starting point because it gives plugin authors the most flexibility and control. One example of an ergonomic abstraction is the Here's a plugin that uses function({ addVariant }) {
addVariant('first-child', ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {
return `.first-child${separator}${className}:first-child`
})
})
} Under the hood, function({ addVariant }) {
addVariant('first-child', ({ container, separator }) => {
container.walkRules(rule => {
const className = rule.selector.slice(1)
rule.selector = `.first-child${separator}${className}:first-child`
})
})
} There might be a way to simplify this even more, for example there's no reason we couldn't allow you to do something like this: function({ addVariant }) {
addVariant('first-child', modifySelectors({ className, separator }) => {
return `.first-child${separator}${className}:first-child`
})
} The only thing about this API is that Either way, by supporting manipulationg via raw PostCSS I've knocked off most of the requirements I mentioned in the opening PR comment, with only "allow plugin authors to control how responsive variants are generated" left to tackle. |
Going to merge this as-is for now and probably include in the next patch release without much ceremony, so I have the option to break it in the next minor if needed which is where I'll probably officially "announce" it and add documentation. |
This feature has been moved behind a flag to make it a bit more explicit that it's subject to change. To enable it (as of 0.6.2 which will be out today): module.exports = {
// ...
experiments: {
pluginVariants: true,
},
} |
## The devDependency [tailwindcss](https://github.com/tailwindcss/tailwindcss) was updated from `0.6.6` to `0.7.0`. This version is **not covered** by your **current version range**. If you don’t accept this pull request, your project will work just like it did before. However, you might be missing out on a bunch of new features, fixes and/or performance improvements from the dependency update. --- <details> <summary>Release Notes for v0.7.0</summary> <ul> <li><a href="#new-features">New Features</a> <ul> <li><a href="#registering-new-variants-from-plugins">Registering new variants from plugins</a></li> <li><a href="#variant-order-can-be-customized-per-module">Variant order can be customized per module</a></li> <li><a href="#added-focus-within-variant">Added <code>focus-within</code> variant</a></li> <li><a href="#fancy-cli-updates">Fancy CLI updates</a></li> <li><a href="#option-to-generate-config-without-comments">Option to generate config without comments</a></li> <li><a href="#make-configured-prefix-optional-when-using-apply">Make configured prefix optional when using <code>@apply</code></a></li> <li><a href="#improve-flexbox-behavior-in-ie">Improve Flexbox behavior in IE 10/11</a></li> </ul> </li> <li><a href="#changes">Changes</a> <ul> <li><a href="#variant-order-in-modules-config-is-now-significant">Variant order in modules is now significant</a></li> <li><a href="#normalize-updated-to-8">Normalize.css updated to v8.0.0</a></li> <li><a href="#removed-css-fix-for-chrome-62-button-border-radius-change">Removed CSS fix for Chrome 62 button border radius change</a></li> </ul> </li> </ul> <p><a name="user-content-new-features"></a></p> <h2>New Features</h2> <p><a name="user-content-registering-new-variants-from-plugins"></a></p> <h3>Registering new variants from plugins (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/505" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/505/hovercard">#505</a>)</h3> <p><em>(Introduced as an experiment in <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/releases/v0.6.2">v0.6.2</a>, now promoted to an official feature)</em></p> <p>Plugins can now add their own variants (like <code>hover</code>, <code>focus</code>, <code>group-hover</code>, etc.) to Tailwind.</p> <p>To get started, destructure the new <code>addVariant</code> function from the object passed to your plugin, and call it with the name of the variant you'd like to add and a callback that can be used to manipulate the PostCSS nodes where the variant is being applied:</p> <div class="highlight highlight-source-js"><pre><span class="pl-c1">module</span>.<span class="pl-smi">exports</span> <span class="pl-k">=</span> { plugins<span class="pl-k">:</span> [ <span class="pl-k">function</span>({ addVariant }) { <span class="pl-en">addVariant</span>(<span class="pl-s"><span class="pl-pds">'</span>important<span class="pl-pds">'</span></span>, ({ container }) <span class="pl-k">=></span> { <span class="pl-smi">container</span>.<span class="pl-en">walkRules</span>(<span class="pl-smi">rule</span> <span class="pl-k">=></span> { <span class="pl-smi">rule</span>.<span class="pl-smi">selector</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">`</span>.<span class="pl-cce">\\</span>!<span class="pl-s1"><span class="pl-pse">${</span><span class="pl-smi">rule</span>.<span class="pl-smi">selector</span>.<span class="pl-c1">slice</span>(<span class="pl-c1">1</span>)<span class="pl-pse">}</span></span><span class="pl-pds">`</span></span> <span class="pl-smi">rule</span>.<span class="pl-en">walkDecls</span>(<span class="pl-smi">decl</span> <span class="pl-k">=></span> { <span class="pl-smi">decl</span>.<span class="pl-smi">important</span> <span class="pl-k">=</span> <span class="pl-c1">true</span> }) }) }) } ] }</pre></div> <p>Documentation is coming soon, but for now learn more in <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/505#issuecomment-400408451" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/505/hovercard">the pull request</a>.</p> <p><a name="user-content-variant-order-can-be-customized-per-module"></a></p> <h3>Variant order can be customized per module (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/505" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/505/hovercard">#505</a>)</h3> <p><em>(Introduced as an experiment in <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/releases/v0.6.2">v0.6.2</a>, now promoted to an official feature)</em></p> <p>Variants are now generated in the order that they are specified in the <code>modules</code> section of your config file, rather than in a hard-coded static order like in previous versions of Tailwind.</p> <p>That means that if you want <code>focus</code> variants to defeat <code>hover</code> variants for background colors, but you want the opposite behavior for border colors, you can actually do that now by specifying the order in your config:</p> <div class="highlight highlight-source-js"><pre><span class="pl-smi">modules</span>.<span class="pl-smi">exports</span> <span class="pl-k">=</span> { <span class="pl-c"><span class="pl-c">//</span> ...</span> modules<span class="pl-k">:</span> { <span class="pl-c"><span class="pl-c">//</span> ...</span> backgroundColors<span class="pl-k">:</span> [<span class="pl-s"><span class="pl-pds">'</span>responsive<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>hover<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>focus<span class="pl-pds">'</span></span>], <span class="pl-c"><span class="pl-c">//</span> ...</span> borderColors<span class="pl-k">:</span> [<span class="pl-s"><span class="pl-pds">'</span>responsive<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>focus<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>hover<span class="pl-pds">'</span></span>], <span class="pl-c"><span class="pl-c">//</span> ...</span> } }</pre></div> <p>Note that this doesn't affect <code>responsive</code> variants — those are a special case since responsive versions are also generated for other variants, and we group responsive declarations to optimize the resulting CSS.</p> <p><a name="user-content-added-focus-within-variant"></a></p> <h3>Added <code>focus-within</code> variant (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/463" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/463/hovercard">#463</a>)</h3> <p>Tailwind now includes a <code>focus-within</code> variant that you can use to change how an element is styled if an element <em>inside</em> of it has focus.</p> <div class="highlight highlight-text-html-basic"><pre><<span class="pl-ent">div</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>focus-within:shadow-lg<span class="pl-pds">"</span></span>> <<span class="pl-ent">label</span>> <<span class="pl-ent">span</span>>Email</<span class="pl-ent">span</span>> <<span class="pl-ent">input</span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>email<span class="pl-pds">"</span></span>> </<span class="pl-ent">label</span>> </<span class="pl-ent">div</span>></pre></div> <p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within" rel="nofollow">Learn about the <code>:focus-within</code> pseudo-class on MDN</a></p> <p>By default we don't generate <code>focus-within</code> variants for any utilities, but you can change this in the modules section your Tailwind configuration file.</p> <p><a name="user-content-fancy-cli-updates"></a></p> <h3>Fancy CLI updates (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/554" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/554/hovercard">#554</a>)</h3> <p>Tailwind 0.7.0 includes a completely rewritten CLI tool with nicer output and a better user experience.</p> <p><a target="_blank" rel="noopener noreferrer" href="https://camo.githubusercontent.com/2d18b961dae3bc67bd8502e7598098e115f3805a/68747470733a2f2f692e696d6775722e636f6d2f6f396e4a536e4f2e676966"><img src="https://camo.githubusercontent.com/2d18b961dae3bc67bd8502e7598098e115f3805a/68747470733a2f2f692e696d6775722e636f6d2f6f396e4a536e4f2e676966" alt="" style="max-width:100%;"></a></p> <p>All of the existing functionality is still there with the same API, it just looks better.</p> <p><a name="user-content-option-to-generate-config-without-comments"></a></p> <h3>Option to generate config without comments (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/558" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/558/hovercard">#558</a>)</h3> <p>You can now use the <code>--no-comments</code> option when running <code>tailwind init</code> to generate a config file that excludes all of the inline documentation comments.</p> <p>This is a great way to make your config file easier to skim if you're an experienced Tailwind user who doesn't need the comments.</p> <p><a name="user-content-make-configured-prefix-optional-when-using-apply"></a></p> <h3>Make configured prefix optional when using <code>@apply</code> (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/553" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/553/hovercard">#553</a>)</h3> <p>If you're <a href="https://tailwindcss.com/docs/configuration/#prefix" rel="nofollow">prefixing</a> your generated utilities, including that prefix when using <code>@apply</code> is now optional.</p> <div class="highlight highlight-source-css"><pre><span class="pl-c"><span class="pl-c">/*</span> Before <span class="pl-c">*/</span></span> <span class="pl-e">.my-component</span> { @<span class="pl-c1">apply</span> <span class="pl-c1">tw-bg-blue</span> <span class="pl-c1">tw-text-white</span> <span class="pl-c1">tw-font-bold</span>; } <span class="pl-c"><span class="pl-c">/*</span> Now <span class="pl-c">*/</span></span> <span class="pl-e">.my-component</span> { @<span class="pl-c1">apply</span> <span class="pl-c1">bg-blue</span> <span class="pl-c1">text-white</span> <span class="pl-c1">font-bold</span>; }</pre></div> <p>You can continue to use the prefix if you like, or drop it if you prefer a terser syntax.</p> <p><a name="user-content-improve-flexbox-behavior-in-ie"></a></p> <h3>Improve Flexbox behavior in IE 10/11 (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/550" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/550/hovercard">#550</a>)</h3> <p>IE 10 and 11 interpret the shorthand <code>flex</code> property differently than other browsers.</p> <p>Tailwind now specifies explicit grow, shrink, and basis values for the <code>flex-1</code>, <code>flex-auto</code>, and <code>flex-initial</code> utilities for a more consistent cross-browser experience.</p> <p><a href="https://urls.greenkeeper.io/philipwalton/flexbugs">Learn more at the flexbugs repo</a> (bugs <a href="https://urls.greenkeeper.io/philipwalton/flexbugs#flexbug-4">#4</a> and <a href="https://urls.greenkeeper.io/philipwalton/flexbugs#flexbug-6">#6</a> specifically)</p> <p><a name="user-content-changes"></a></p> <h2>Changes</h2> <p><a name="user-content-variant-order-in-modules-config-is-now-significant"></a></p> <h3>Variant order in modules config is now significant (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/505" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/505/hovercard">#505</a>)</h3> <p><em>Impact: Low, Effort: Low</em></p> <p>Prior to 0.7.0, variants were always generated in the same order, regardless of the order specified in the <code>modules</code> section of your config file.</p> <p>Now, variants are generated in the they are specified. That means that if your config file currently lists variants in a different order than the <=0.6.6 default variant order, those variants will appear in a different order in your CSS.</p> <p>To preserve the <=0.6.6 behavior, simply edit the <code>modules</code> section of your config file to make sure your variants are listed in the following order:</p> <div class="highlight highlight-source-js"><pre><span class="pl-smi">modules</span>.<span class="pl-smi">exports</span> <span class="pl-k">=</span> { <span class="pl-c"><span class="pl-c">//</span> ...</span> modules<span class="pl-k">:</span> { <span class="pl-c"><span class="pl-c">//</span> ...</span> [anyModule]<span class="pl-k">:</span> [<span class="pl-s"><span class="pl-pds">'</span>group-hover<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>hover<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>focus-within<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>focus<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>active<span class="pl-pds">'</span></span>] <span class="pl-c"><span class="pl-c">//</span> ...</span> } }</pre></div> <p><a name="user-content-normalize-updated-to-8"></a></p> <h3>Normalize.css updated to v8.0.0 (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/537" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/537/hovercard">#537</a>)</h3> <p><em>Impact: Low, Effort: Low</em></p> <p>We've updated our dependency on <a href="https://urls.greenkeeper.io/necolas/normalize.css">Normalize.css</a> from 7.0.0 to 8.0.0.</p> <p>This drops support for very old browsers like IE9, Android 4.3, Safari 8, and iOS Safari 7-8.</p> <p>If you still need to support those browsers, remove <code>@tailwind preflight</code> from your CSS, add Normalize.css 7.0.0 to your project, and manually add our <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/blob/46ea06e6d6cb3196be17a2b81c5c9a5e7e4a304d/css/preflight.css#L449-L585">additional preflight base styles</a>.</p> <p><a name="user-content-removed-css-fix-for-chrome-62-button-border-radius-change"></a></p> <h3>Removed CSS fix for Chrome 62 button border radius change (<a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/579" data-hovercard-type="pull_request" data-hovercard-url="/tailwindlabs/tailwindcss/pull/579/hovercard">#579</a>)</h3> <p><em>Impact: Low, Effort: Low</em></p> <p>When Chrome 62 was released, it introduced a user agent stylesheet change that added a default border radius to all buttons.</p> <p>This messed up styles for like half of the internet (including sites like GitHub itself), so Chrome reverted the change in Chrome 63.</p> <p>We included a fix for this in Tailwind with the intention to remove it when Chrome 62 was no longer in common use. Now that usage has dropped to 0.09%, we've removed our fix.</p> <p>If this is a problem for you <em>(it isn't)</em>, you can add <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/pull/579/files#diff-328b7fa9880734a59bf8dab8bfe8c12a">the removed styles</a> back to your project right after <code>@tailwind preflight</code>.</p> </details> <details> <summary>Commits</summary> <p>The new version differs by 60 commits ahead by 60, behind by 2.</p> <ul> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/4f5ad9031fb9b90235a24ce9f090034e17ba9594"><code>4f5ad90</code></a> <code>0.7.0</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/1e8a70b68cf93fe9162272a121d7da2875d4b130"><code>1e8a70b</code></a> <code>Promote pluginVariants from experiment to feature</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/58f10b626bb4cc13ed89d6fab86ad9cd8a6afcda"><code>58f10b6</code></a> <code>Update lockfile</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/35f8dd6acf3b9623fb1e8806c813b83dc1f78f5a"><code>35f8dd6</code></a> <code>Merge pull request #579 from Ambyjkl/master</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/331454f62dd1bdaf57dae266097255fc8f8c70b1"><code>331454f</code></a> <code>Undo CSS override for Chrome 62</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/7120a89fde888dcfc3b67a02d2f9e5751c09f959"><code>7120a89</code></a> <code>Merge pull request #576 from motleydev/master</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/55f8207d214650b9dc11371f0a5d7a5024be2bda"><code>55f8207</code></a> <code>Fix apostrophe in error</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/335c1b1f1d58e3d8a1f199dfffc52fb763fea98e"><code>335c1b1</code></a> <code>Merge pull request #573 from willemvb/patch-1</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/8dab134aaf61d6599b6bf1019c8e4513cafa4c26"><code>8dab134</code></a> <code>Update defaultConfig.stub.js</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/7c9029ac2bb598c95e9edd9bfa3789a379a165db"><code>7c9029a</code></a> <code>Update Slack invite link</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/c4c36b9955c0a500dd521a1bd13ceac5ed14699a"><code>c4c36b9</code></a> <code>Merge pull request #558 from MattStypa/init-no-comments</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/34ad504a469e0b3477a013ef7cbe7199271ddf47"><code>34ad504</code></a> <code>Added tests for CLI utils</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/dbeeea4dbb4375c8091fd649feaef5314aa57eeb"><code>dbeeea4</code></a> <code>Added ability to protect comments when --no-comments options is use for CLI init command</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/48387a8f8ac753a6480c2842ceebad36660595e6"><code>48387a8</code></a> <code>Switched to use strip-comments instead of Babel for CLI init command</code></li> <li><a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/commit/9e26fd84e35743aa08f20eaddadb2aff9a8a6c00"><code>9e26fd8</code></a> <code>CLI. Added --no-comments option to init commend</code></li> </ul> <p>There are 60 commits in total.</p> <p>See the <a href="https://urls.greenkeeper.io/tailwindcss/tailwindcss/compare/62ae545a271ddf17dcc9f3218526ec0b42c336c7...4f5ad9031fb9b90235a24ce9f090034e17ba9594">full diff</a></p> </details> <details> <summary>FAQ and help</summary> There is a collection of [frequently asked questions](https://greenkeeper.io/faq.html). If those don’t help, you can always [ask the humans behind Greenkeeper](https://github.com/greenkeeperio/greenkeeper/issues/new). </details> --- Your [Greenkeeper](https://greenkeeper.io) bot 🌴
Implementation for #496.
Right now this PR adds support for basic variant plugins that just alter the selector, like our bundled variants.
It lets you write a plugin like this to create a
first-child
variant:It also changes how the order variants are generated in is determined, by pushing that control to the user instead of using a hard-coded order. Now the order of your variants in your
modules
config is the order we use to generate the variants, so if you list['hover, 'focus']
, hover will be generated first, but if you list['focus', 'hover']
then focus will be generated first. This puts the user in control of which rule takes precedence.Next up:
supports-grid
variant)