Skip to content

Commit 06df6d5

Browse files
committed
v4: Show completions after any valid variant
We weren’t handling the case of arbitrary variants, variants with an arbitrary value, and variants with bare values. We have to compile a dummy class temporarily to determine whether or not the class is valid
1 parent a3b39d2 commit 06df6d5

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

packages/tailwindcss-language-server/tests/completions/completions.test.js

+92-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { test } from 'vitest'
1+
import { test, expect, describe } from 'vitest'
22
import { withFixture } from '../common'
3+
import { css, defineTest } from '../../src/testing'
4+
import { createClient } from '../utils/client'
35

46
function buildCompletion(c) {
57
return async function completion({
@@ -670,3 +672,92 @@ withFixture('v4/workspaces', (c) => {
670672
})
671673
})
672674
})
675+
676+
defineTest({
677+
name: 'v4: Completions show after a variant arbitrary value',
678+
fs: {
679+
'app.css': css`
680+
@import 'tailwindcss';
681+
`,
682+
},
683+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
684+
handle: async ({ client }) => {
685+
let document = await client.open({
686+
lang: 'html',
687+
text: '<div class="data-[foo]:">',
688+
})
689+
690+
// <div class="data-[foo]:">
691+
// ^
692+
let completion = await document.completions({ line: 0, character: 23 })
693+
694+
expect(completion?.items.length).toBe(12289)
695+
},
696+
})
697+
698+
defineTest({
699+
name: 'v4: Completions show after an arbitrary variant',
700+
fs: {
701+
'app.css': css`
702+
@import 'tailwindcss';
703+
`,
704+
},
705+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
706+
handle: async ({ client }) => {
707+
let document = await client.open({
708+
lang: 'html',
709+
text: '<div class="[&:hover]:">',
710+
})
711+
712+
// <div class="[&:hover]:">
713+
// ^
714+
let completion = await document.completions({ line: 0, character: 22 })
715+
716+
expect(completion?.items.length).toBe(12289)
717+
},
718+
})
719+
720+
defineTest({
721+
name: 'v4: Completions show after a variant with a bare value',
722+
fs: {
723+
'app.css': css`
724+
@import 'tailwindcss';
725+
`,
726+
},
727+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
728+
handle: async ({ client }) => {
729+
let document = await client.open({
730+
lang: 'html',
731+
text: '<div class="supports-not-hover:">',
732+
})
733+
734+
// <div class="supports-not-hover:">
735+
// ^
736+
let completion = await document.completions({ line: 0, character: 31 })
737+
738+
expect(completion?.items.length).toBe(12289)
739+
},
740+
})
741+
742+
defineTest({
743+
options: { only: true },
744+
name: 'v4: Partial compound variants show completions',
745+
fs: {
746+
'app.css': css`
747+
@import 'tailwindcss';
748+
`,
749+
},
750+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
751+
handle: async ({ client }) => {
752+
let document = await client.open({
753+
lang: 'html',
754+
text: '<div class="not-supports-display:">',
755+
})
756+
757+
// <div class="not-supports-display:">
758+
// ^
759+
let completion = await document.completions({ line: 0, character: 33 })
760+
761+
expect(completion?.items.length).toBe(12289)
762+
},
763+
})

packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts

+13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ export function getVariantsFromClassName(
2929

3030
let className = `${part}${state.separator}[color:red]`
3131

32+
if (state.v4) {
33+
// NOTE: This should never happen
34+
if (!state.designSystem) return false
35+
36+
// We don't use `compile()` so there's no overhead from PostCSS
37+
let compiled = state.designSystem.candidatesToCss([className])
38+
39+
// NOTE: This should never happen
40+
if (compiled.length !== 1) return false
41+
42+
return compiled[0] !== null
43+
}
44+
3245
if (state.jit) {
3346
if ((part.includes('[') && part.endsWith(']')) || part.includes('/')) {
3447
return jit.generateRules(state, [className]).rules.length > 0

0 commit comments

Comments
 (0)