-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Improve addVariant
API
#5809
Merged
Merged
Improve addVariant
API
#5809
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Probably messed this up in another PR, so just a bit of cleaning.
This will be used to eventually simplify the addVariant API. The idea is that it can take a list of strings that define a certain format. Then it squashes everything to a single format how you would expect it. E.g.: Input: - '&:hover' - '&:focus' - '.dark &' - ':merge(.group):hover &' - ':merge(.group):focus &' Output: - ':merge(.group):focus:hover .dark &:focus:hover' The API here is: - `&`, this means "The parent" or "The previous selector" (you can think of it like if you are using nested selectors) - `:merge(.group)`, this means insert a `.group` if it doesn't exist yet, but if it does exist already, then merge the new value with the old value. This allows us to merge group-focus, group-hover into a single `.group:focus:hover ...`
This will ensure that the backwards compatibility for `modifySelectors` and direct mutations to the `container` will still work. We will try to capture the changes made to the `rule.selector`, we will also "backup" the existing selector. This allows us to diff the old and new selectors and determine what actually happened. Once we know this, we can restore the selector to the "old" selector and add the diffed string e.g.: `.foo &`, to the `collectedFormats` as if you called `format()` directly. This is a bunch of extra work, but it allows us to be backwards compatible. In the future we could also warn if you are using `modifySelectors`, but it is going to be a little bit tricky, because usually that's implemented by plugin authors and therefore you don't have direct control over this. Maybe we can figure out the plugin this is used in and change the warning somehow?
This was clearly a bug, keyframes should not include escaped variants at all. The reason this is here in the first place is because the nodes in a keyframe are also "rule" nodes.
The current implementation had a strange side effect, that resulted in incorrect class definitions. When you are combining the `:hover` and `:focus` event, then there is no difference between `:hover:focus` and `:focus:hover`. However, when you use `:hover::file-selector-button` or `::file-selector-button:hover`, then there is a big difference. In the first place, you can hover over the full file input to apply changes to the `File selector button`. In the second scenario you have to hover over the `File selector button` itself to apply changes. You can think of it as function calls: - focus(hover(text-center)) What you would expect is something like this: `.focus\:hover\:text-center:hover:focus`, where `hover` is on the inside, and `focus` is on the outside. However in the current implementation this is implemented as `.focus\:hover\:text-cener:focus:hover`
We can get rid of this because we drastically simplified the new addVariant API.
The current API looks like this: ```js addVariant('name', ({ format, wrap }) => { // Wrap in an atRule wrap(postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: reduce)' })) // "Mutate" the selector, for example prepend `.dark` format('.dark &') }) ``` It is also pretty common to have this: ```js addVariant('name', ({ format }) => format('.dark &')) ``` So we simplified this to: ```js addVariant('name', '.dark &') ``` It is also pretty common to have this: ```js addVariant('name', ({ wrap }) => wrap(postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: reduce)' }))) ``` So we simplified this to: ```js addVariant('name', '@media (prefers-reduced-motion: reduce)') ```
We will use `@defaults`, so that only the resets are injected for the utilities we actually use.
RobinMalfait
force-pushed
the
improve-add-variant-api
branch
from
October 18, 2021 09:23
684f7f1
to
fb05ee2
Compare
david-crespo
added a commit
to oxidecomputer/console
that referenced
this pull request
Nov 16, 2021
david-crespo
added a commit
to oxidecomputer/console
that referenced
this pull request
Nov 17, 2021
* upgrade to tailwind 3.0 alpha, make config changes * rewrite svg: w/ new addVariant API tailwindlabs/tailwindcss#5809 * first first-of-type:before: order issue (tw fix in next alpha) tailwindlabs/tailwindcss#6112 tailwindlabs/tailwindcss#6016 tailwindlabs/tailwindcss#6018 * replace tailwindcss-children plugin with new custom addVariant * oh yeah... use stroke-green-500 * each variant doesn't need its own plugin * update yarn.lock after merging main
45 tasks
seanpdoyle
added a commit
to thoughtbot/tailwindcss-aria-attributes
that referenced
this pull request
Jul 28, 2022
Re-implement variants using the newly String-based `addVariant` plugin method changed in [tailwindlabs/tailwindcss#5809][]. [tailwindlabs/tailwindcss#5809]: tailwindlabs/tailwindcss#5809
seanpdoyle
added a commit
to thoughtbot/tailwindcss-aria-attributes
that referenced
this pull request
Jul 28, 2022
Re-implement variants using the newly String-based `addVariant` plugin method changed in [tailwindlabs/tailwindcss#5809][]. [tailwindlabs/tailwindcss#5809]: tailwindlabs/tailwindcss#5809
seanpdoyle
added a commit
to thoughtbot/tailwindcss-aria-attributes
that referenced
this pull request
Jul 28, 2022
Re-implement variants using the newly String-based `addVariant` plugin method changed in [tailwindlabs/tailwindcss#5809][]. [tailwindlabs/tailwindcss#5809]: tailwindlabs/tailwindcss#5809
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR will improve and drastically simplify the
addVariant
API. This is an API that is important to us internally, and also for plugin authors. If you don't write plugins yourself, then this PR doesn't really matter to you.The API we had was very verbose, but it made sense if you think about how AOT mode worked. In AOT mode, we generated all the css you could ever need. This means that we didn't know what you were actually using. Plugin authors then had to keep multiple things into account. For starters they need to know how a selector is structured, for example
first-letter${config('separator')}${className}
. For JIT mode this doesn't really make sense, because we start from the content files. This means that we already know the final className (because we extracted it from the content files), and rebuilding this className by hand means that you can only do it perfect, or introduce errors if you for example forget the old className, or if you forget to read the separator from thetailwind.config.js
file.Long story short, we can hugely simplify this...
I will get into more API details soon, but let's just look at some before/after implementations for existing variants.
First Letter
A "simple" variant, that adds a pseudo element.
Before:
After:
Marker
A variant that has parallel variants.
Before:
After:
Group hover
A variant that adds a parent selector, but should also re-use he existing
.group
if it already exists.Before:
After:
API
The verbose
addVariant
now has new functions it exposes in the callback.format(/* format string */)
&
, this is a symbol that references the selector it is applying to. We don't need to rebuild the full selector manually, we already have all that information. But now you can prepend/append anything to it.:merge()
pseudo, which allows you to merge states together in case you are using multiple variants. Let's explain this with an example instead (1).wrap(/* PostCSS Node, E.g.: AtRule */)
Full example:
Format
The format function accepts a string where you can prepend or append other parts of a selector to the existing selector.
&
The
&
symbol in theformat
function is referring to the "previous" or "parent" selector. You don't have to rebuild this full selector yourself, because we already know what the final className should look like.For example, the
hover
variant, is implemented like this:This means that if you are using
hover:text-center
, that the final result would be.hover\:text-center:hover
Another example is dark mode, using the
class
mode.This means that if you are using
dark:text-center
, that the final result would be.dark .dark\:text-center
:merge()
The
:merge(.class)
pseudo/function inside your format string allows you to merge with existing classes if they already exist, if not, it would be inserted. Let's explain it with an example.Imagine you want to implement the
group-hover
variant:This means, that if you are using
group-hover:text-center
, that your final resul would be.group:hover .group-hover\:text-center
. This is correct and what you expect.However, let's imagine you want to implement the
group-focus
variant:But this time, you are using
group-hover:group-focus:text-center
, this means that the final result would look like this:.group:hover .group:focus .group-hover\:group-focus\:text-center
, this is incorrect, we don't want two.group
classes at the front. What we expect is.group:hover:focus .group-hover\:group-focus\:text-center
.This is where the
:merge
comes in. We want to merge the.group
class in this case.We also have two
addVariant
shorthands.The current API looks like this:
It is also pretty common to have this:
So we simplified this to:
It is also pretty common to have this:
So we simplified this to:
The last shorthand is to combine
@media
and&
related formats.