@@ -20,8 +20,6 @@ export function getVariantsFromClassName(
2020 return { variants : [ ] , offset : 0 }
2121 }
2222
23- parts = parts . filter ( Boolean )
24-
2523 function isValidVariant ( part : string ) {
2624 if ( allVariants . includes ( part ) ) {
2725 return true
@@ -60,11 +58,36 @@ export function getVariantsFromClassName(
6058 let offset = 0
6159 let variants = new Set < string > ( )
6260
63- for ( let part of parts ) {
61+ for ( let [ index , part ] of parts . entries ( ) ) {
62+ // If we see an empty variant it's because:
63+ //
64+ // - The string contains consecutive top-level separators, e.g.
65+ // hover::flex
66+ // - The string *ends* with a `:` which is a signal that the variant is done
67+ // and more should be suggested
68+
69+ // The first case isn't a valid class, partial or otherwise. The second one
70+ // *is* valid because a user is probably in the middle of typing a utility.
71+ //
72+ // In both situations a `break` is sufficient to signal that the remainder
73+ // of the string should be ignored when determining variants.
74+ if ( part === '' ) break
6475 if ( ! isValidVariant ( part ) ) break
6576
6677 variants . add ( part )
67- offset += part . length + state . separator ! . length
78+
79+ offset += part . length
80+
81+ // All variants must be succeeded by the separator (`:`) when used in a
82+ // utility. However, Tailwind CSS <= v4.1.15 has a bug where we consider
83+ // `bg-[` valid because we try to compile `bg-[:[color:red]` which in turn
84+ // parses as a valid class when it obviously is not.
85+ //
86+ // To combat this we've done two things:
87+ // - Add the offset to all variants *except* the last one
88+ // - Allow an empty string in the last position to account for situations
89+ // where a utility name is currently being typed (e.g. `hover:`)
90+ offset += index < parts . length - 1 ? state . separator ! . length : 0
6891 }
6992
7093 return { variants : Array . from ( variants ) , offset }
0 commit comments