+ // ^
+ let completion = await document.completions({ line: 0, character: 12 })
+
+ expect(completion?.items.length).toBe(19237)
+
+ // Verify that variants and utilities are all prefixed
+ let prefixed = completion.items.filter((item) => !item.label.startsWith('tw:'))
+ expect(prefixed).toHaveLength(0)
+ },
+})
+
+defineTest({
+ name: 'v4: Variant and utility suggestions hide prefix when it has been typed',
+ fs: {
+ 'app.css': css`
+ @import 'tailwindcss' prefix(tw);
+ `,
+ },
+ prepare: async ({ root }) => ({ client: await createClient({ root }) }),
+ handle: async ({ client }) => {
+ let document = await client.open({
+ lang: 'html',
+ text: '
',
+ })
+
+ //
+ // ^
+ let completion = await document.completions({ line: 0, character: 15 })
+
+ expect(completion?.items.length).toBe(19236)
+
+ // Verify that no variants and utilities have prefixes
+ let prefixed = completion.items.filter((item) => item.label.startsWith('tw:'))
+ expect(prefixed).toHaveLength(0)
+ },
+})
+
defineTest({
name: 'v4: Completions show inside class functions in JS/TS files',
fs: {
diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts
index 5c0c5552..843e9a8e 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -261,29 +261,25 @@ export function completionsFromClassList(
// TODO: This is a bit of a hack
if (prefix.length > 0) {
- // No variants seen: suggest the prefix only
+ // No variants seen:
+ // - suggest the prefix as a variant
+ // - Modify the remaining items to include the prefix in the variant name
if (existingVariants.length === 0) {
- items = items.slice(0, 1)
+ items = items.map((item, idx) => {
+ if (idx === 0) return item
- return withDefaults(
- {
- isIncomplete: false,
- items,
- },
- {
- data: {
- ...(state.completionItemData ?? {}),
- ...(important ? { important } : {}),
- variants: existingVariants,
- },
- range: replacementRange,
- },
- state.editor.capabilities.itemDefaults,
- )
+ item.label = `${prefix}:${item.label}`
+
+ if (item.textEditText) {
+ item.textEditText = `${prefix}:${item.textEditText}`
+ }
+
+ return item
+ })
}
// The first variant is not the prefix: don't suggest anything
- if (existingVariants[0] !== prefix) {
+ if (existingVariants.length > 0 && existingVariants[0] !== prefix) {
return null
}
}
@@ -304,6 +300,10 @@ export function completionsFromClassList(
documentation = formatColor(color)
}
+ if (prefix.length > 0 && existingVariants.length === 0) {
+ className = `${prefix}:${className}`
+ }
+
items.push({
label: className,
kind,
diff --git a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
index c30e729a..823b20f8 100644
--- a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
+++ b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
@@ -33,6 +33,12 @@ export function getVariantsFromClassName(
// NOTE: This should never happen
if (!state.designSystem) return false
+ let prefix = state.designSystem.theme.prefix ?? ''
+
+ if (prefix !== '') {
+ className = `${prefix}:${className}`
+ }
+
// We don't use `compile()` so there's no overhead from PostCSS
let compiled = state.designSystem.candidatesToCss([className])