-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* register arbitrary variants With the new `addVariant` API, we have a beautiful way of creating new variants. You can use it as: ```js addVariant('children', '& > *') ``` Now you can use the `children:` variant. The API uses a `&` as a reference for the candidate, which means that: ```html children:pl-4 ``` Will result in: ```css .children\:pl-4 > * { .. } ``` Notice that the `&` was replaced by `.children\:pl-4`. We can leverage this API to implement arbitrary variants, this means that you can write those `&>*` (Notice that we don't have spaces) inside a variant directly. An example of this can be: ```html <ul class="[&>*]:underline"> <li>A</li> <li>B</li> <li>C</li> </ul> ``` Which generates the following css: ```css .\[\&\>\*\]\:underline > * { text-decoration-line: underline; } ``` Now all the children of the `ul` will have an `underline`. The selector itself is a bit crazy since it contains the candidate which is the selector itself, it is just escaped. * add tests for arbitrary variants This still requires some work to the `defaultExtractor` to make sure it all works with existing code. * update changelog * Fix candidate detection for arbitrary variants * Refactor * Add support for at rules * Add test for attribute selectors * Fix test * Add attribute selector support * Split top-level comma parsing into a generalized splitting routine We can now split on any character at the top level with any nesting. We don’t balance brackets directly here but this is probably “enough” * Split variants by separator at the top-level only This means that the separator has to be ouside of balanced brackets * Fix extraction when using custom variant separators * Support custom separators when top-level splitting variants * Add a second multi-character separator test * Split tests for at-rule and at-rule with selector changes * Add nested at-rule tests * Fix space-less at-rule parsing in addVariant * Add test for using with `@apply` Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
- Loading branch information
1 parent
cea3ccf
commit be51739
Showing
9 changed files
with
525 additions
and
88 deletions.
There are no files selected for viewing
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
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
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
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import * as regex from '../lib/regex' | ||
|
||
/** | ||
* This splits a string on a top-level character. | ||
* | ||
* Regex doesn't support recursion (at least not the JS-flavored version). | ||
* So we have to use a tiny state machine to keep track of paren placement. | ||
* | ||
* Expected behavior using commas: | ||
* var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0) | ||
* ─┬─ ┬ ┬ ┬ | ||
* x x x ╰──────── Split because top-level | ||
* ╰──────────────┴──┴───────────── Ignored b/c inside >= 1 levels of parens | ||
* | ||
* @param {string} input | ||
* @param {string} separator | ||
*/ | ||
export function* splitAtTopLevelOnly(input, separator) { | ||
let SPECIALS = new RegExp(`[(){}\\[\\]${regex.escape(separator)}]`, 'g') | ||
|
||
let depth = 0 | ||
let lastIndex = 0 | ||
let found = false | ||
let separatorIndex = 0 | ||
let separatorStart = 0 | ||
let separatorLength = separator.length | ||
|
||
// Find all paren-like things & character | ||
// And only split on commas if they're top-level | ||
for (let match of input.matchAll(SPECIALS)) { | ||
let matchesSeparator = match[0] === separator[separatorIndex] | ||
let atEndOfSeparator = separatorIndex === separatorLength - 1 | ||
let matchesFullSeparator = matchesSeparator && atEndOfSeparator | ||
|
||
if (match[0] === '(') depth++ | ||
if (match[0] === ')') depth-- | ||
if (match[0] === '[') depth++ | ||
if (match[0] === ']') depth-- | ||
if (match[0] === '{') depth++ | ||
if (match[0] === '}') depth-- | ||
|
||
if (matchesSeparator && depth === 0) { | ||
if (separatorStart === 0) { | ||
separatorStart = match.index | ||
} | ||
|
||
separatorIndex++ | ||
} | ||
|
||
if (matchesFullSeparator && depth === 0) { | ||
found = true | ||
|
||
yield input.substring(lastIndex, separatorStart) | ||
lastIndex = separatorStart + separatorLength | ||
} | ||
|
||
if (separatorIndex === separatorLength) { | ||
separatorIndex = 0 | ||
separatorStart = 0 | ||
} | ||
} | ||
|
||
// Provide the last segment of the string if available | ||
// Otherwise the whole string since no `char`s were found | ||
// This mirrors the behavior of string.split() | ||
if (found) { | ||
yield input.substring(lastIndex) | ||
} else { | ||
yield input | ||
} | ||
} |
Oops, something went wrong.