From 8a4a60d9fc8af71a7c7205ef839def1b6d69d51a Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 14 Apr 2025 13:54:34 -0400 Subject: [PATCH 1/3] Add failing test --- packages/tailwindcss/src/intellisense.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/tailwindcss/src/intellisense.test.ts b/packages/tailwindcss/src/intellisense.test.ts index 04a6ed7961b9..f5902a2613df 100644 --- a/packages/tailwindcss/src/intellisense.test.ts +++ b/packages/tailwindcss/src/intellisense.test.ts @@ -653,3 +653,25 @@ test('shadow utility default suggestions', async () => { expect(classNames).toContain('inset-shadow') expect(classNames).toContain('text-shadow') }) + +test('Custom @utility and existing utility with names matching theme keys dont give duplicate results', async () => { + let input = css` + @theme reference { + --leading-sm: 0.25rem; + --text-header: 1.5rem; + } + + @utility text-header { + text-transform: uppercase; + } + ` + + let design = await __unstable__loadDesignSystem(input) + + let classList = design.getClassList() + let classMap = new Map(classList) + let matches = classList.filter(([className]) => className === 'text-header') + + expect(matches).toHaveLength(1) + expect(classMap.get('text-header')?.modifiers).toEqual(['sm']) +}) From 2e5e1f9a964c4e8dc7dd3a341011366b341a957c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 14 Apr 2025 14:04:11 -0400 Subject: [PATCH 2/3] Ensure class suggestions are unique --- packages/tailwindcss/src/intellisense.ts | 39 ++++++++++++------------ 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/tailwindcss/src/intellisense.ts b/packages/tailwindcss/src/intellisense.ts index ca9c1a386099..27db3a540bc3 100644 --- a/packages/tailwindcss/src/intellisense.ts +++ b/packages/tailwindcss/src/intellisense.ts @@ -20,16 +20,18 @@ export type ClassEntry = [string, ClassMetadata] const IS_FRACTION = /^\d+\/\d+$/ export function getClassList(design: DesignSystem): ClassEntry[] { - let list: ClassItem[] = [] + let items = new DefaultMap((utility) => ({ + name: utility, + utility, + fraction: false, + modifiers: [], + })) // Static utilities only work as-is for (let utility of design.utilities.keys('static')) { - list.push({ - name: utility, - utility, - fraction: false, - modifiers: [], - }) + let item = items.get(utility) + item.fraction = false + item.modifiers = [] } // Functional utilities have their own list of completions @@ -42,28 +44,25 @@ export function getClassList(design: DesignSystem): ClassEntry[] { let name = value === null ? utility : `${utility}-${value}` - list.push({ - name, - utility, - fraction, - modifiers: group.modifiers, - }) + let item = items.get(name) + item.utility = utility + item.fraction ||= fraction + item.modifiers.push(...group.modifiers) if (group.supportsNegative) { - list.push({ - name: `-${name}`, - utility: `-${utility}`, - fraction, - modifiers: group.modifiers, - }) + let item = items.get(`-${name}`) + item.utility = `-${utility}` + item.fraction ||= fraction + item.modifiers.push(...group.modifiers) } } } } - if (list.length === 0) return [] + if (items.size === 0) return [] // Sort utilities by their class name + let list = Array.from(items.values()) list.sort((a, b) => compare(a.name, b.name)) let entries = sortFractionsLast(list) From 57300d572ec01560b17cf833a27543e43e9fb873 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 9 May 2025 13:37:48 -0400 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d76daf0fb56..9f146b04446b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Allow `_` before numbers during candidate extraction ([#17961](https://github.com/tailwindlabs/tailwindcss/pull/17961)) +- Prevent duplicate suggestions when using `@theme` and `@utility` together ([#17675](https://github.com/tailwindlabs/tailwindcss/pull/17675)) ## [4.1.6] - 2025-05-09