Skip to content

Commit 43b9dfa

Browse files
committed
use splitModifiers function instead of regex to support arbitrary variants
1 parent 3c44743 commit 43b9dfa

File tree

1 file changed

+37
-12
lines changed

1 file changed

+37
-12
lines changed

src/lib/merge-classlist.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ import { ConfigUtils } from './config-utils'
22

33
const SPLIT_CLASSES_REGEX = /\s+/
44
const IMPORTANT_MODIFIER = '!'
5-
// Regex is needed, so we don't match against colons in labels for arbitrary values like `text-[color:var(--mystery-var)]`
6-
// I'd prefer to use a negative lookbehind for all supported labels, but lookbehinds don't have good browser support yet. More info: https://caniuse.com/js-regexp-lookbehind
7-
const MODIFIER_SEPARATOR_REGEX = /:(?![^[]*\])/
85
const MODIFIER_SEPARATOR = ':'
96

107
export function mergeClassList(classList: string, configUtils: ConfigUtils) {
@@ -24,16 +21,10 @@ export function mergeClassList(classList: string, configUtils: ConfigUtils) {
2421
.trim()
2522
.split(SPLIT_CLASSES_REGEX)
2623
.map((originalClassName) => {
27-
const modifiers = originalClassName.split(MODIFIER_SEPARATOR_REGEX)
28-
const classNameWithImportantModifier = modifiers.pop()!
24+
const { modifiers, hasImportantModifier, baseClassName } =
25+
splitModifiers(originalClassName)
2926

30-
const hasImportantModifier =
31-
classNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)
32-
const className = hasImportantModifier
33-
? classNameWithImportantModifier.substring(1)
34-
: classNameWithImportantModifier
35-
36-
const classGroupId = getClassGroupId(className)
27+
const classGroupId = getClassGroupId(baseClassName)
3728

3829
if (!classGroupId) {
3930
return {
@@ -86,3 +77,37 @@ export function mergeClassList(classList: string, configUtils: ConfigUtils) {
8677
.join(' ')
8778
)
8879
}
80+
81+
function splitModifiers(className: string) {
82+
const modifiers = []
83+
84+
let bracketDepth = 0
85+
let modifierStart = 0
86+
87+
for (const match of className.matchAll(/[:[\]]/g)) {
88+
if (match[0] === ':') {
89+
if (bracketDepth === 0) {
90+
const nextModifierStart = match.index! + 1
91+
modifiers.push(className.substring(modifierStart, nextModifierStart))
92+
modifierStart = nextModifierStart
93+
}
94+
} else if (match[0] === '[') {
95+
bracketDepth++
96+
} else if (match[0] === ']') {
97+
bracketDepth--
98+
}
99+
}
100+
101+
const baseClassNameWithImportantModifier =
102+
modifiers.length === 0 ? className : className.substring(modifierStart)
103+
const hasImportantModifier = baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)
104+
const baseClassName = hasImportantModifier
105+
? baseClassNameWithImportantModifier.substring(1)
106+
: baseClassNameWithImportantModifier
107+
108+
return {
109+
modifiers,
110+
hasImportantModifier,
111+
baseClassName,
112+
}
113+
}

0 commit comments

Comments
 (0)