This PR adds support for the `matchVariant` plugin API. I've copied over
all [V3
tests](f07dbff2a7/tests/match-variants.test.js)
and made sure they still pass.
## Sorted order of stacked arbitrary variants
The only difference in behavior is regarding the sort order of stacked
arbitrary variants: Sorting in this case now works by the latest defined
`matchVariant` taking precedence.
So, if you define a plugin like this:
```ts
matchVariant('testmin', (value) => `@media (min-width: ${value})`, {
sort(a, z) {
return parseInt(a.value) - parseInt(z.value)
},
})
matchVariant('testmax', (value) => `@media (max-width: ${value})`, {
sort(a, z) {
return parseInt(z.value) - parseInt(a.value)
},
})
```
The resulting CSS is first sorted by the `testmax` values descending and
then the `testmin` values ascending, so these candidates:
```txt
testmin-[150px]:testmax-[400px]:order-2
testmin-[100px]:testmax-[350px]:order-3
testmin-[100px]:testmax-[300px]:order-4
testmin-[100px]:testmax-[400px]:order-1
```
Will resolve to the order outlined by the `order-` utility.
## At-rules and placeholders support
Since we added support for at-rules and placeholders in the
`matchVariant` syntax like this:
```ts
matchVariant(
'potato',
(flavor) => `@media (potato: ${flavor}) { @supports (font:bold) { &:large-potato } }`,
)
```
We also added support for the same syntax to the `addVariant` API:
```ts
addVariant(
'potato',
'@media (max-width: 400px) { @supports (font:bold) { &:large-potato } }',
)
```
The only change necessary in core was to call functional variants for
when the variant value is set to `null`. This allows functional variants
to define the un-parameterized implementation like `potato:underline` as
opposed to `potato[big]:underline`.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>