@@ -1275,6 +1275,66 @@ function provideVariantsDirectiveCompletions(
1275
1275
)
1276
1276
}
1277
1277
1278
+ function provideVariantDirectiveCompletions (
1279
+ state : State ,
1280
+ document : TextDocument ,
1281
+ position : Position ,
1282
+ ) : CompletionList {
1283
+ if ( ! state . v4 ) return null
1284
+ if ( ! isCssContext ( state , document , position ) ) return null
1285
+
1286
+ let text = document . getText ( {
1287
+ start : { line : position . line , character : 0 } ,
1288
+ end : position ,
1289
+ } )
1290
+
1291
+ let match = text . match ( / ^ \s * @ v a r i a n t \s + (?< partial > [ ^ } ] * ) $ / i)
1292
+ if ( match === null ) return null
1293
+
1294
+ let partial = match . groups . partial . trim ( )
1295
+
1296
+ // We only allow one variant `@variant` call
1297
+ if ( / \s / . test ( partial ) ) return null
1298
+
1299
+ // We don't allow applying stacked variants so don't suggest them
1300
+ if ( / : / . test ( partial ) ) return null
1301
+
1302
+ let possibleVariants = state . variants . flatMap ( ( variant ) => {
1303
+ if ( variant . values . length ) {
1304
+ return variant . values . map ( ( value ) =>
1305
+ value === 'DEFAULT' ? variant . name : `${ variant . name } ${ variant . hasDash ? '-' : '' } ${ value } ` ,
1306
+ )
1307
+ }
1308
+
1309
+ return [ variant . name ]
1310
+ } )
1311
+
1312
+ return withDefaults (
1313
+ {
1314
+ isIncomplete : false ,
1315
+ items : possibleVariants . map ( ( variant , index , variants ) => ( {
1316
+ label : variant ,
1317
+ kind : 21 ,
1318
+ sortText : naturalExpand ( index , variants . length ) ,
1319
+ } ) ) ,
1320
+ } ,
1321
+ {
1322
+ data : {
1323
+ ...( state . completionItemData ?? { } ) ,
1324
+ _type : 'variant' ,
1325
+ } ,
1326
+ range : {
1327
+ start : {
1328
+ line : position . line ,
1329
+ character : position . character ,
1330
+ } ,
1331
+ end : position ,
1332
+ } ,
1333
+ } ,
1334
+ state . editor . capabilities . itemDefaults ,
1335
+ )
1336
+ }
1337
+
1278
1338
function provideLayerDirectiveCompletions (
1279
1339
state : State ,
1280
1340
document : TextDocument ,
@@ -1423,6 +1483,8 @@ function provideCssDirectiveCompletions(
1423
1483
1424
1484
if ( match === null ) return null
1425
1485
1486
+ let isNested = isInsideNesting ( document , position )
1487
+
1426
1488
let items : CompletionItem [ ] = [ ]
1427
1489
1428
1490
items . push ( {
@@ -1535,12 +1597,12 @@ function provideCssDirectiveCompletions(
1535
1597
} )
1536
1598
1537
1599
items . push ( {
1538
- label : '@variant' ,
1600
+ label : '@custom- variant' ,
1539
1601
documentation : {
1540
1602
kind : 'markdown' as typeof MarkupKind . Markdown ,
1541
- value : `Use the \`@variant\` directive to define a custom variant or override an existing one.\n\n[Tailwind CSS Documentation](${ docsUrl (
1603
+ value : `Use the \`@custom- variant\` directive to define a custom variant or override an existing one.\n\n[Tailwind CSS Documentation](${ docsUrl (
1542
1604
state . version ,
1543
- 'functions-and-directives/#variant' ,
1605
+ 'functions-and-directives/#custom- variant' ,
1544
1606
) } )`,
1545
1607
} ,
1546
1608
} )
@@ -1566,9 +1628,22 @@ function provideCssDirectiveCompletions(
1566
1628
) } )`,
1567
1629
} ,
1568
1630
} )
1631
+ }
1569
1632
1570
- // If we're inside an @variant directive, also add `@slot`
1571
- if ( isInsideAtRule ( 'variant' , document , position ) ) {
1633
+ if ( state . v4 && isNested ) {
1634
+ items . push ( {
1635
+ label : '@variant' ,
1636
+ documentation : {
1637
+ kind : 'markdown' as typeof MarkupKind . Markdown ,
1638
+ value : `Use the \`@variant\` directive to use a variant in CSS.\n\n[Tailwind CSS Documentation](${ docsUrl (
1639
+ state . version ,
1640
+ 'functions-and-directives/variant' ,
1641
+ ) } )`,
1642
+ } ,
1643
+ } )
1644
+
1645
+ // If we're inside an @custom-variant directive, also add `@slot`
1646
+ if ( isInsideAtRule ( 'custom-variant' , document , position ) ) {
1572
1647
items . push ( {
1573
1648
label : '@slot' ,
1574
1649
documentation : {
@@ -1611,20 +1686,29 @@ function provideCssDirectiveCompletions(
1611
1686
}
1612
1687
1613
1688
function isInsideAtRule ( name : string , document : TextDocument , position : Position ) {
1614
- // 1. Get all text up to the current position
1615
1689
let text = document . getText ( {
1616
1690
start : { line : 0 , character : 0 } ,
1617
1691
end : position ,
1618
1692
} )
1619
1693
1620
- // 2. Find the last instance of the at-rule
1694
+ // Find the last instance of the at-rule
1621
1695
let block = text . lastIndexOf ( `@${ name } ` )
1622
1696
if ( block === - 1 ) return false
1623
1697
1624
- // 4. Count the number of open and close braces following the rule to determine if we're inside it
1698
+ // Check if we're inside it by counting the number of still-open braces
1625
1699
return braceLevel ( text . slice ( block ) ) > 0
1626
1700
}
1627
1701
1702
+ function isInsideNesting ( document : TextDocument , position : Position ) {
1703
+ let text = document . getText ( {
1704
+ start : { line : 0 , character : 0 } ,
1705
+ end : position ,
1706
+ } )
1707
+
1708
+ // Check if we're inside a rule by counting the number of still-open braces
1709
+ return braceLevel ( text ) > 0
1710
+ }
1711
+
1628
1712
// Provide completions for directives that take file paths
1629
1713
const PATTERN_AT_THEME = / @ (?< directive > t h e m e ) \s + (?: (?< parts > [ ^ { ] + ) \s $ | $ ) /
1630
1714
const PATTERN_IMPORT_THEME = / @ (?< directive > i m p o r t ) \s * [ ^ ; ] + ?t h e m e \( (?: (?< parts > [ ^ ) ] + ) \s $ | $ ) /
@@ -1874,6 +1958,7 @@ export async function doComplete(
1874
1958
provideCssHelperCompletions ( state , document , position ) ||
1875
1959
provideCssDirectiveCompletions ( state , document , position ) ||
1876
1960
provideScreenDirectiveCompletions ( state , document , position ) ||
1961
+ provideVariantDirectiveCompletions ( state , document , position ) ||
1877
1962
provideVariantsDirectiveCompletions ( state , document , position ) ||
1878
1963
provideTailwindDirectiveCompletions ( state , document , position ) ||
1879
1964
provideLayerDirectiveCompletions ( state , document , position ) ||
0 commit comments