From 13f11069c80a54cae38bc3368a545ca93e45aead Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:24:37 -0500 Subject: [PATCH 1/8] Add radius utilities and deprecated rounded utilities --- .../src/__snapshots__/index.test.ts.snap | 8 - .../src/__snapshots__/index.test.ts.snap | 8 - .../__snapshots__/intellisense.test.ts.snap | 540 ++++++++++++++++++ packages/tailwindcss/src/utilities.ts | 35 +- packages/tailwindcss/theme.css | 24 +- playgrounds/vite/src/app.tsx | 3 + 6 files changed, 590 insertions(+), 28 deletions(-) diff --git a/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap b/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap index 24d0c8fa484d..81a1ac5608a3 100644 --- a/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap +++ b/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap @@ -271,14 +271,6 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` --blur-xl: 24px; --blur-2xl: 40px; --blur-3xl: 64px; - --radius-xs: .125rem; - --radius-sm: .25rem; - --radius-md: .375rem; - --radius-lg: .5rem; - --radius-xl: .75rem; - --radius-2xl: 1rem; - --radius-3xl: 1.5rem; - --radius-4xl: 2rem; --shadow-2xs: 0 1px #0000000d; --shadow-xs: 0 1px 2px 0 #0000000d; --shadow-sm: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; diff --git a/packages/tailwindcss/src/__snapshots__/index.test.ts.snap b/packages/tailwindcss/src/__snapshots__/index.test.ts.snap index 760d4a9ec6f5..ccbabeb34d33 100644 --- a/packages/tailwindcss/src/__snapshots__/index.test.ts.snap +++ b/packages/tailwindcss/src/__snapshots__/index.test.ts.snap @@ -270,14 +270,6 @@ exports[`compiling CSS > \`@tailwind utilities\` is replaced by utilities using --blur-xl: 24px; --blur-2xl: 40px; --blur-3xl: 64px; - --radius-xs: .125rem; - --radius-sm: .25rem; - --radius-md: .375rem; - --radius-lg: .5rem; - --radius-xl: .75rem; - --radius-2xl: 1rem; - --radius-3xl: 1.5rem; - --radius-4xl: 2rem; --shadow-2xs: 0 1px #0000000d; --shadow-xs: 0 1px 2px 0 #0000000d; --shadow-sm: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; diff --git a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap index 0b4723c64b7c..f22ec2a0f377 100644 --- a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap +++ b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap @@ -5051,6 +5051,546 @@ exports[`getClassList 1`] = ` "py-9", "py-96", "py-px", + "radius-0", + "radius-0.5", + "radius-1", + "radius-1.5", + "radius-10", + "radius-11", + "radius-12", + "radius-14", + "radius-16", + "radius-2", + "radius-2.5", + "radius-20", + "radius-24", + "radius-28", + "radius-3", + "radius-3.5", + "radius-32", + "radius-36", + "radius-4", + "radius-40", + "radius-44", + "radius-48", + "radius-5", + "radius-52", + "radius-56", + "radius-6", + "radius-60", + "radius-64", + "radius-7", + "radius-72", + "radius-8", + "radius-80", + "radius-9", + "radius-96", + "radius-b-0", + "radius-b-0.5", + "radius-b-1", + "radius-b-1.5", + "radius-b-10", + "radius-b-11", + "radius-b-12", + "radius-b-14", + "radius-b-16", + "radius-b-2", + "radius-b-2.5", + "radius-b-20", + "radius-b-24", + "radius-b-28", + "radius-b-3", + "radius-b-3.5", + "radius-b-32", + "radius-b-36", + "radius-b-4", + "radius-b-40", + "radius-b-44", + "radius-b-48", + "radius-b-5", + "radius-b-52", + "radius-b-56", + "radius-b-6", + "radius-b-60", + "radius-b-64", + "radius-b-7", + "radius-b-72", + "radius-b-8", + "radius-b-80", + "radius-b-9", + "radius-b-96", + "radius-b-full", + "radius-b-px", + "radius-bl-0", + "radius-bl-0.5", + "radius-bl-1", + "radius-bl-1.5", + "radius-bl-10", + "radius-bl-11", + "radius-bl-12", + "radius-bl-14", + "radius-bl-16", + "radius-bl-2", + "radius-bl-2.5", + "radius-bl-20", + "radius-bl-24", + "radius-bl-28", + "radius-bl-3", + "radius-bl-3.5", + "radius-bl-32", + "radius-bl-36", + "radius-bl-4", + "radius-bl-40", + "radius-bl-44", + "radius-bl-48", + "radius-bl-5", + "radius-bl-52", + "radius-bl-56", + "radius-bl-6", + "radius-bl-60", + "radius-bl-64", + "radius-bl-7", + "radius-bl-72", + "radius-bl-8", + "radius-bl-80", + "radius-bl-9", + "radius-bl-96", + "radius-bl-full", + "radius-bl-px", + "radius-br-0", + "radius-br-0.5", + "radius-br-1", + "radius-br-1.5", + "radius-br-10", + "radius-br-11", + "radius-br-12", + "radius-br-14", + "radius-br-16", + "radius-br-2", + "radius-br-2.5", + "radius-br-20", + "radius-br-24", + "radius-br-28", + "radius-br-3", + "radius-br-3.5", + "radius-br-32", + "radius-br-36", + "radius-br-4", + "radius-br-40", + "radius-br-44", + "radius-br-48", + "radius-br-5", + "radius-br-52", + "radius-br-56", + "radius-br-6", + "radius-br-60", + "radius-br-64", + "radius-br-7", + "radius-br-72", + "radius-br-8", + "radius-br-80", + "radius-br-9", + "radius-br-96", + "radius-br-full", + "radius-br-px", + "radius-e-0", + "radius-e-0.5", + "radius-e-1", + "radius-e-1.5", + "radius-e-10", + "radius-e-11", + "radius-e-12", + "radius-e-14", + "radius-e-16", + "radius-e-2", + "radius-e-2.5", + "radius-e-20", + "radius-e-24", + "radius-e-28", + "radius-e-3", + "radius-e-3.5", + "radius-e-32", + "radius-e-36", + "radius-e-4", + "radius-e-40", + "radius-e-44", + "radius-e-48", + "radius-e-5", + "radius-e-52", + "radius-e-56", + "radius-e-6", + "radius-e-60", + "radius-e-64", + "radius-e-7", + "radius-e-72", + "radius-e-8", + "radius-e-80", + "radius-e-9", + "radius-e-96", + "radius-e-full", + "radius-e-px", + "radius-ee-0", + "radius-ee-0.5", + "radius-ee-1", + "radius-ee-1.5", + "radius-ee-10", + "radius-ee-11", + "radius-ee-12", + "radius-ee-14", + "radius-ee-16", + "radius-ee-2", + "radius-ee-2.5", + "radius-ee-20", + "radius-ee-24", + "radius-ee-28", + "radius-ee-3", + "radius-ee-3.5", + "radius-ee-32", + "radius-ee-36", + "radius-ee-4", + "radius-ee-40", + "radius-ee-44", + "radius-ee-48", + "radius-ee-5", + "radius-ee-52", + "radius-ee-56", + "radius-ee-6", + "radius-ee-60", + "radius-ee-64", + "radius-ee-7", + "radius-ee-72", + "radius-ee-8", + "radius-ee-80", + "radius-ee-9", + "radius-ee-96", + "radius-ee-full", + "radius-ee-px", + "radius-es-0", + "radius-es-0.5", + "radius-es-1", + "radius-es-1.5", + "radius-es-10", + "radius-es-11", + "radius-es-12", + "radius-es-14", + "radius-es-16", + "radius-es-2", + "radius-es-2.5", + "radius-es-20", + "radius-es-24", + "radius-es-28", + "radius-es-3", + "radius-es-3.5", + "radius-es-32", + "radius-es-36", + "radius-es-4", + "radius-es-40", + "radius-es-44", + "radius-es-48", + "radius-es-5", + "radius-es-52", + "radius-es-56", + "radius-es-6", + "radius-es-60", + "radius-es-64", + "radius-es-7", + "radius-es-72", + "radius-es-8", + "radius-es-80", + "radius-es-9", + "radius-es-96", + "radius-es-full", + "radius-es-px", + "radius-full", + "radius-l-0", + "radius-l-0.5", + "radius-l-1", + "radius-l-1.5", + "radius-l-10", + "radius-l-11", + "radius-l-12", + "radius-l-14", + "radius-l-16", + "radius-l-2", + "radius-l-2.5", + "radius-l-20", + "radius-l-24", + "radius-l-28", + "radius-l-3", + "radius-l-3.5", + "radius-l-32", + "radius-l-36", + "radius-l-4", + "radius-l-40", + "radius-l-44", + "radius-l-48", + "radius-l-5", + "radius-l-52", + "radius-l-56", + "radius-l-6", + "radius-l-60", + "radius-l-64", + "radius-l-7", + "radius-l-72", + "radius-l-8", + "radius-l-80", + "radius-l-9", + "radius-l-96", + "radius-l-full", + "radius-l-px", + "radius-px", + "radius-r-0", + "radius-r-0.5", + "radius-r-1", + "radius-r-1.5", + "radius-r-10", + "radius-r-11", + "radius-r-12", + "radius-r-14", + "radius-r-16", + "radius-r-2", + "radius-r-2.5", + "radius-r-20", + "radius-r-24", + "radius-r-28", + "radius-r-3", + "radius-r-3.5", + "radius-r-32", + "radius-r-36", + "radius-r-4", + "radius-r-40", + "radius-r-44", + "radius-r-48", + "radius-r-5", + "radius-r-52", + "radius-r-56", + "radius-r-6", + "radius-r-60", + "radius-r-64", + "radius-r-7", + "radius-r-72", + "radius-r-8", + "radius-r-80", + "radius-r-9", + "radius-r-96", + "radius-r-full", + "radius-r-px", + "radius-s-0", + "radius-s-0.5", + "radius-s-1", + "radius-s-1.5", + "radius-s-10", + "radius-s-11", + "radius-s-12", + "radius-s-14", + "radius-s-16", + "radius-s-2", + "radius-s-2.5", + "radius-s-20", + "radius-s-24", + "radius-s-28", + "radius-s-3", + "radius-s-3.5", + "radius-s-32", + "radius-s-36", + "radius-s-4", + "radius-s-40", + "radius-s-44", + "radius-s-48", + "radius-s-5", + "radius-s-52", + "radius-s-56", + "radius-s-6", + "radius-s-60", + "radius-s-64", + "radius-s-7", + "radius-s-72", + "radius-s-8", + "radius-s-80", + "radius-s-9", + "radius-s-96", + "radius-s-full", + "radius-s-px", + "radius-se-0", + "radius-se-0.5", + "radius-se-1", + "radius-se-1.5", + "radius-se-10", + "radius-se-11", + "radius-se-12", + "radius-se-14", + "radius-se-16", + "radius-se-2", + "radius-se-2.5", + "radius-se-20", + "radius-se-24", + "radius-se-28", + "radius-se-3", + "radius-se-3.5", + "radius-se-32", + "radius-se-36", + "radius-se-4", + "radius-se-40", + "radius-se-44", + "radius-se-48", + "radius-se-5", + "radius-se-52", + "radius-se-56", + "radius-se-6", + "radius-se-60", + "radius-se-64", + "radius-se-7", + "radius-se-72", + "radius-se-8", + "radius-se-80", + "radius-se-9", + "radius-se-96", + "radius-se-full", + "radius-se-px", + "radius-ss-0", + "radius-ss-0.5", + "radius-ss-1", + "radius-ss-1.5", + "radius-ss-10", + "radius-ss-11", + "radius-ss-12", + "radius-ss-14", + "radius-ss-16", + "radius-ss-2", + "radius-ss-2.5", + "radius-ss-20", + "radius-ss-24", + "radius-ss-28", + "radius-ss-3", + "radius-ss-3.5", + "radius-ss-32", + "radius-ss-36", + "radius-ss-4", + "radius-ss-40", + "radius-ss-44", + "radius-ss-48", + "radius-ss-5", + "radius-ss-52", + "radius-ss-56", + "radius-ss-6", + "radius-ss-60", + "radius-ss-64", + "radius-ss-7", + "radius-ss-72", + "radius-ss-8", + "radius-ss-80", + "radius-ss-9", + "radius-ss-96", + "radius-ss-full", + "radius-ss-px", + "radius-t-0", + "radius-t-0.5", + "radius-t-1", + "radius-t-1.5", + "radius-t-10", + "radius-t-11", + "radius-t-12", + "radius-t-14", + "radius-t-16", + "radius-t-2", + "radius-t-2.5", + "radius-t-20", + "radius-t-24", + "radius-t-28", + "radius-t-3", + "radius-t-3.5", + "radius-t-32", + "radius-t-36", + "radius-t-4", + "radius-t-40", + "radius-t-44", + "radius-t-48", + "radius-t-5", + "radius-t-52", + "radius-t-56", + "radius-t-6", + "radius-t-60", + "radius-t-64", + "radius-t-7", + "radius-t-72", + "radius-t-8", + "radius-t-80", + "radius-t-9", + "radius-t-96", + "radius-t-full", + "radius-t-px", + "radius-tl-0", + "radius-tl-0.5", + "radius-tl-1", + "radius-tl-1.5", + "radius-tl-10", + "radius-tl-11", + "radius-tl-12", + "radius-tl-14", + "radius-tl-16", + "radius-tl-2", + "radius-tl-2.5", + "radius-tl-20", + "radius-tl-24", + "radius-tl-28", + "radius-tl-3", + "radius-tl-3.5", + "radius-tl-32", + "radius-tl-36", + "radius-tl-4", + "radius-tl-40", + "radius-tl-44", + "radius-tl-48", + "radius-tl-5", + "radius-tl-52", + "radius-tl-56", + "radius-tl-6", + "radius-tl-60", + "radius-tl-64", + "radius-tl-7", + "radius-tl-72", + "radius-tl-8", + "radius-tl-80", + "radius-tl-9", + "radius-tl-96", + "radius-tl-full", + "radius-tl-px", + "radius-tr-0", + "radius-tr-0.5", + "radius-tr-1", + "radius-tr-1.5", + "radius-tr-10", + "radius-tr-11", + "radius-tr-12", + "radius-tr-14", + "radius-tr-16", + "radius-tr-2", + "radius-tr-2.5", + "radius-tr-20", + "radius-tr-24", + "radius-tr-28", + "radius-tr-3", + "radius-tr-3.5", + "radius-tr-32", + "radius-tr-36", + "radius-tr-4", + "radius-tr-40", + "radius-tr-44", + "radius-tr-48", + "radius-tr-5", + "radius-tr-52", + "radius-tr-56", + "radius-tr-6", + "radius-tr-60", + "radius-tr-64", + "radius-tr-7", + "radius-tr-72", + "radius-tr-8", + "radius-tr-80", + "radius-tr-9", + "radius-tr-96", + "radius-tr-full", + "radius-tr-px", "relative", "resize", "resize-none", diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index f57c4cccec9d..88c2119e855b 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -1931,8 +1931,11 @@ export function createUtilities(theme: Theme) { staticUtility('break-all', [['word-break', 'break-all']]) staticUtility('break-keep', [['word-break', 'break-keep']]) + /** + * @css `border-radius` + */ { - // border-radius + // Deprecated: `rounded` utilities for (let [root, properties] of [ ['rounded', ['border-radius']], ['rounded-s', ['border-start-start-radius', 'border-end-start-radius']], @@ -1959,10 +1962,38 @@ export function createUtilities(theme: Theme) { properties.map((property) => [property, 'calc(infinity * 1px)']), ) functionalUtility(root, { - themeKeys: ['--radius'], + themeKeys: ['--radius', '--rounded'], handle: (value) => properties.map((property) => decl(property, value)), }) } + + // `radius-*` utilities + for (let [root, properties] of [ + ['radius', ['border-radius']], + ['radius-s', ['border-start-start-radius', 'border-end-start-radius']], + ['radius-e', ['border-start-end-radius', 'border-end-end-radius']], + ['radius-t', ['border-top-left-radius', 'border-top-right-radius']], + ['radius-r', ['border-top-right-radius', 'border-bottom-right-radius']], + ['radius-b', ['border-bottom-right-radius', 'border-bottom-left-radius']], + ['radius-l', ['border-top-left-radius', 'border-bottom-left-radius']], + ['radius-ss', ['border-start-start-radius']], + ['radius-se', ['border-start-end-radius']], + ['radius-ee', ['border-end-end-radius']], + ['radius-es', ['border-end-start-radius']], + ['radius-tl', ['border-top-left-radius']], + ['radius-tr', ['border-top-right-radius']], + ['radius-br', ['border-bottom-right-radius']], + ['radius-bl', ['border-bottom-left-radius']], + ] as const) { + staticUtility( + `${root}-full`, + properties.map((property) => [property, 'calc(infinity * 1px)']), + ) + + spacingUtility(root, '--radius', (value) => + properties.map((property) => decl(property, value)), + ) + } } staticUtility('border-solid', [ diff --git a/packages/tailwindcss/theme.css b/packages/tailwindcss/theme.css index ba6d9a538c64..965e03bee832 100644 --- a/packages/tailwindcss/theme.css +++ b/packages/tailwindcss/theme.css @@ -299,16 +299,6 @@ --blur-2xl: 40px; --blur-3xl: 64px; - /* Radii */ - --radius-xs: 0.125rem; - --radius-sm: 0.25rem; - --radius-md: 0.375rem; - --radius-lg: 0.5rem; - --radius-xl: 0.75rem; - --radius-2xl: 1rem; - --radius-3xl: 1.5rem; - --radius-4xl: 2rem; - /* Shadows */ --shadow-2xs: 0 1px rgb(0 0 0 / 0.05); --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); @@ -458,3 +448,17 @@ } } } + +/** + * @deprecated + */ +@theme default inline reference { + --rounded: 0.25rem; + --rounded-sm: 0.125rem; + --rounded-md: 0.375rem; + --rounded-lg: 0.5rem; + --rounded-xl: 0.75rem; + --rounded-2xl: 1rem; + --rounded-3xl: 1.5rem; + --rounded-4xl: 2rem; +} diff --git a/playgrounds/vite/src/app.tsx b/playgrounds/vite/src/app.tsx index 8ec50298951f..8f41e3da7255 100644 --- a/playgrounds/vite/src/app.tsx +++ b/playgrounds/vite/src/app.tsx @@ -2,6 +2,9 @@ export function App() { return (

Hello World

+ +
+
) } From 34d4376130353cec400d3a300454a4928527087c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 05:01:44 -0500 Subject: [PATCH 2/8] Remove `string` SuggestionDefinition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This isn’t used --- packages/tailwindcss/src/utilities.ts | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index 88c2119e855b..5682c31794d8 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -16,16 +16,14 @@ interface SuggestionGroup { modifiers: string[] } -type SuggestionDefinition = - | string - | { - supportsNegative?: boolean - values?: string[] - modifiers?: string[] - valueThemeKeys?: ThemeKey[] - modifierThemeKeys?: ThemeKey[] - hasDefaultValue?: boolean - } +type SuggestionDefinition = { + supportsNegative?: boolean + values?: string[] + modifiers?: string[] + valueThemeKeys?: ThemeKey[] + modifierThemeKeys?: ThemeKey[] + hasDefaultValue?: boolean +} export type UtilityOptions = { types: string[] @@ -213,11 +211,6 @@ export function createUtilities(theme: Theme) { let groups: SuggestionGroup[] = [] for (let defn of defns()) { - if (typeof defn === 'string') { - groups.push({ values: [defn], modifiers: [] }) - continue - } - let values: (string | null)[] = [ ...(defn.values ?? []), ...resolve(defn.valueThemeKeys ?? []), From 632c418ff451c63ecac0bcdfbe29ab7125be3924 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 05:03:24 -0500 Subject: [PATCH 3/8] Allow utilities to be marked as deprecated --- packages/tailwindcss/src/intellisense.test.ts | 2 +- packages/tailwindcss/src/intellisense.ts | 16 +++++++++++++--- packages/tailwindcss/src/utilities.ts | 9 ++++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/tailwindcss/src/intellisense.test.ts b/packages/tailwindcss/src/intellisense.test.ts index cccf3d4eb14a..f11fb9619373 100644 --- a/packages/tailwindcss/src/intellisense.test.ts +++ b/packages/tailwindcss/src/intellisense.test.ts @@ -36,7 +36,7 @@ test('Theme values with underscores are converted back to decimal points', () => let design = loadDesignSystem() let classes = design.getClassList() - expect(classes).toContainEqual(['inset-0.5', { modifiers: [] }]) + expect(classes).toContainEqual(['inset-0.5', { modifiers: [], deprecated: false }]) }) test('getVariants', () => { diff --git a/packages/tailwindcss/src/intellisense.ts b/packages/tailwindcss/src/intellisense.ts index 5713afda43cd..6b7d74fdac3a 100644 --- a/packages/tailwindcss/src/intellisense.ts +++ b/packages/tailwindcss/src/intellisense.ts @@ -4,6 +4,7 @@ import type { DesignSystem } from './design-system' interface ClassMetadata { modifiers: string[] + deprecated: boolean } export type ClassEntry = [string, ClassMetadata] @@ -13,7 +14,16 @@ export function getClassList(design: DesignSystem): ClassEntry[] { // Static utilities only work as-is for (let utility of design.utilities.keys('static')) { - list.push([utility, { modifiers: [] }]) + let completions = design.utilities.getCompletions(utility) + let deprecated = completions.length > 0 && completions.every((group) => group.deprecated) + + list.push([ + utility, + { + modifiers: [], + deprecated, + }, + ]) } // Functional utilities have their own list of completions @@ -24,10 +34,10 @@ export function getClassList(design: DesignSystem): ClassEntry[] { for (let value of group.values) { let name = value === null ? utility : `${utility}-${value}` - list.push([name, { modifiers: group.modifiers }]) + list.push([name, { modifiers: group.modifiers, deprecated: group.deprecated }]) if (group.supportsNegative) { - list.push([`-${name}`, { modifiers: group.modifiers }]) + list.push([`-${name}`, { modifiers: group.modifiers, deprecated: group.deprecated }]) } } } diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index 5682c31794d8..dc4bbf5389ac 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -14,6 +14,7 @@ interface SuggestionGroup { supportsNegative?: boolean values: (string | null)[] modifiers: string[] + deprecated: boolean } type SuggestionDefinition = { @@ -23,6 +24,7 @@ type SuggestionDefinition = { valueThemeKeys?: ThemeKey[] modifierThemeKeys?: ThemeKey[] hasDefaultValue?: boolean + deprecated?: boolean } export type UtilityOptions = { @@ -221,7 +223,12 @@ export function createUtilities(theme: Theme) { values.unshift(null) } - groups.push({ supportsNegative: defn.supportsNegative, values, modifiers }) + groups.push({ + supportsNegative: defn.supportsNegative, + values, + modifiers, + deprecated: defn.deprecated ?? false, + }) } return groups From a25d4ab1a63b8cc385a7174debcca68fd59770a0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 05:03:00 -0500 Subject: [PATCH 4/8] Deprecate `rounded-*` utilities --- .../__snapshots__/intellisense.test.ts.snap | 35 +++++++++++++++++++ packages/tailwindcss/src/intellisense.test.ts | 12 +++++++ packages/tailwindcss/src/utilities.ts | 9 +++++ 3 files changed, 56 insertions(+) diff --git a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap index f22ec2a0f377..64535b672421 100644 --- a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap +++ b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap @@ -1,5 +1,40 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`deprecated classes 1`] = ` +[ + "rounded-b-full", + "rounded-b-none", + "rounded-bl-full", + "rounded-bl-none", + "rounded-br-full", + "rounded-br-none", + "rounded-e-full", + "rounded-e-none", + "rounded-ee-full", + "rounded-ee-none", + "rounded-es-full", + "rounded-es-none", + "rounded-full", + "rounded-l-full", + "rounded-l-none", + "rounded-none", + "rounded-r-full", + "rounded-r-none", + "rounded-s-full", + "rounded-s-none", + "rounded-se-full", + "rounded-se-none", + "rounded-ss-full", + "rounded-ss-none", + "rounded-t-full", + "rounded-t-none", + "rounded-tl-full", + "rounded-tl-none", + "rounded-tr-full", + "rounded-tr-none", +] +`; + exports[`getClassList 1`] = ` [ "-bottom-0", diff --git a/packages/tailwindcss/src/intellisense.test.ts b/packages/tailwindcss/src/intellisense.test.ts index f11fb9619373..4f5e8c06a2b8 100644 --- a/packages/tailwindcss/src/intellisense.test.ts +++ b/packages/tailwindcss/src/intellisense.test.ts @@ -32,6 +32,18 @@ test('getClassList', () => { expect(classNames).toMatchSnapshot() }) +test('deprecated classes', () => { + let design = loadDesignSystem() + let classList = design.getClassList() + classList = classList.filter(([_, meta]) => meta.deprecated) + let classNames = classList.flatMap(([name, meta]) => [ + name, + ...meta.modifiers.map((m) => `${name}/${m}`), + ]) + + expect(classNames).toMatchSnapshot() +}) + test('Theme values with underscores are converted back to decimal points', () => { let design = loadDesignSystem() let classes = design.getClassList() diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index dc4bbf5389ac..de822034c810 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -1965,6 +1965,15 @@ export function createUtilities(theme: Theme) { themeKeys: ['--radius', '--rounded'], handle: (value) => properties.map((property) => decl(property, value)), }) + + suggest(`${root}-none`, () => [{ deprecated: true }]) + suggest(`${root}-full`, () => [{ deprecated: true }]) + suggest(root, () => [ + { + valueThemeKeys: ['--radius'], + deprecated: true, + }, + ]) } // `radius-*` utilities From 63e3b6924ed88bb5ec29f0a00893052e82a9ad1f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 05:07:28 -0500 Subject: [PATCH 5/8] Fix type error --- packages/tailwindcss/src/compat/plugin-api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/tailwindcss/src/compat/plugin-api.ts b/packages/tailwindcss/src/compat/plugin-api.ts index 04fb8d43a59d..36957d2c7d65 100644 --- a/packages/tailwindcss/src/compat/plugin-api.ts +++ b/packages/tailwindcss/src/compat/plugin-api.ts @@ -380,6 +380,7 @@ export function buildPluginApi( supportsNegative: options?.supportsNegativeValues ?? false, values: Array.from(valueKeys), modifiers: modifierKeys, + deprecated: false, }, ] }) From f0d52e00b2faf6024d3c92a1963e066a74a73c8b Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 07:23:10 -0500 Subject: [PATCH 6/8] Add `deprecated` theme option --- packages/tailwindcss/src/index.ts | 2 ++ packages/tailwindcss/src/theme.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 40663f4883b8..a4edd92bd37c 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -61,6 +61,8 @@ function parseThemeOptions(params: string) { options |= ThemeOptions.INLINE } else if (option === 'default') { options |= ThemeOptions.DEFAULT + } else if (option === 'deprecated') { + options |= ThemeOptions.DEPRECATED } else if (option.startsWith('prefix(') && option.endsWith(')')) { prefix = option.slice(7, -1) } diff --git a/packages/tailwindcss/src/theme.ts b/packages/tailwindcss/src/theme.ts index 389b469941f6..71c450997653 100644 --- a/packages/tailwindcss/src/theme.ts +++ b/packages/tailwindcss/src/theme.ts @@ -6,6 +6,7 @@ export const enum ThemeOptions { INLINE = 1 << 0, REFERENCE = 1 << 1, DEFAULT = 1 << 2, + DEPRECATED = 1 << 3, } // In the future we may want to replace this with just a `Set` of known theme From 9d6b2ae20467dd6081fed358610ea4232cc24fb0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 08:27:16 -0500 Subject: [PATCH 7/8] wip --- packages/tailwindcss/src/design-system.ts | 13 +- packages/tailwindcss/src/intellisense.test.ts | 15 ++ packages/tailwindcss/src/intellisense.ts | 66 +++++- packages/tailwindcss/src/utilities.ts | 194 +++++++++++------- 4 files changed, 206 insertions(+), 82 deletions(-) diff --git a/packages/tailwindcss/src/design-system.ts b/packages/tailwindcss/src/design-system.ts index 894dba6eaae2..7f35576534fa 100644 --- a/packages/tailwindcss/src/design-system.ts +++ b/packages/tailwindcss/src/design-system.ts @@ -1,7 +1,14 @@ import { toCss } from './ast' import { parseCandidate, parseVariant, type Candidate, type Variant } from './candidate' import { compileAstNodes, compileCandidates } from './compile' -import { getClassList, getVariants, type ClassEntry, type VariantEntry } from './intellisense' +import { + getClassList, + getClassMetadata, + getVariants, + type ClassEntry, + type ClassMetadata, + type VariantEntry, +} from './intellisense' import { getClassOrder } from './sort' import type { Theme, ThemeKey } from './theme' import { Utilities, createUtilities, withAlpha } from './utilities' @@ -31,6 +38,7 @@ export type DesignSystem = { // Used by IntelliSense candidatesToCss(classes: string[]): (string | null)[] + classMetadata(classes: string[]): (ClassMetadata | null)[] } export function buildDesignSystem(theme: Theme): DesignSystem { @@ -74,6 +82,9 @@ export function buildDesignSystem(theme: Theme): DesignSystem { return result }, + classMetadata(classes: string[]) { + return getClassMetadata(this, classes) + }, getClassOrder(classes) { return getClassOrder(this, classes) diff --git a/packages/tailwindcss/src/intellisense.test.ts b/packages/tailwindcss/src/intellisense.test.ts index 4f5e8c06a2b8..67ecca9747ff 100644 --- a/packages/tailwindcss/src/intellisense.test.ts +++ b/packages/tailwindcss/src/intellisense.test.ts @@ -441,3 +441,18 @@ test('Custom at-rule variants do not show up as a value under `group`', async () expect(not.values).toContain('variant-3') expect(not.values).toContain('variant-4') }) + +test.only('getClassMetadata(…)', async () => { + let input = css` + @tailwind utilities; + ` + + let design = await __unstable__loadDesignSystem(input) + + expect(design.classMetadata(['rounded'])).toEqual([ + { + modifiers: [], + deprecated: true, + }, + ]) +}) diff --git a/packages/tailwindcss/src/intellisense.ts b/packages/tailwindcss/src/intellisense.ts index 6b7d74fdac3a..e86ba8f08ea9 100644 --- a/packages/tailwindcss/src/intellisense.ts +++ b/packages/tailwindcss/src/intellisense.ts @@ -2,20 +2,82 @@ import { styleRule, walkDepth } from './ast' import { applyVariant } from './compile' import type { DesignSystem } from './design-system' -interface ClassMetadata { +export interface ClassMetadata { modifiers: string[] deprecated: boolean } export type ClassEntry = [string, ClassMetadata] +export function getClassMetadata( + design: DesignSystem, + classes: string[], +): (ClassMetadata | null)[] { + let list: (ClassMetadata | null)[] = [] + + for (let className of classes) { + let candidates = design.parseCandidate(className) + if (candidates.length === 0) { + list.push(null) + continue + } + + let modifiers: string[] = [] + let deprecated: boolean[] = [] + + for (let candidate of candidates) { + if (candidate.kind === 'arbitrary') continue + if (candidate.kind === 'static') continue + + let utilities = design.utilities.get(candidate.root) + let completions = design.utilities.getCompletions(candidate.root) + + let isDeprecated = utilities.every((utility) => utility.options?.deprecated ?? false) + + for (let group of completions) { + if (group.values.length === 0) continue + + for (let value of group.values) { + if (value === null && candidate.value === null) { + modifiers.push(...group.modifiers) + + if (group.deprecated) isDeprecated = true + } else if (candidate.value?.kind === 'named' && value === candidate.value.value) { + modifiers.push(...group.modifiers) + + if (group.deprecated) isDeprecated = true + } + } + } + + deprecated.push(isDeprecated) + } + + list.push({ + modifiers, + + // When multiple candidates are generated and only some are deprecated we + // we will not report that the class is deprecated because of ambiguity. + // Marking it as such is not useful because the user might be using it for + // the non-deprecated purpose from of a plugin. + deprecated: deprecated.length > 0 && deprecated.every((value) => value), + }) + } + + return list +} + export function getClassList(design: DesignSystem): ClassEntry[] { let list: [string, ClassMetadata][] = [] // Static utilities only work as-is for (let utility of design.utilities.keys('static')) { + let utilities = design.utilities.get(utility) let completions = design.utilities.getCompletions(utility) - let deprecated = completions.length > 0 && completions.every((group) => group.deprecated) + + let deprecated = + utilities.every((utility) => utility.options?.deprecated ?? false) || + (completions.length > 0 && completions.every((group) => group.deprecated)) list.push([ utility, diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index de822034c810..c5a3fca2c366 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -1,6 +1,6 @@ import { atRoot, atRule, decl, styleRule, type AstNode } from './ast' import type { Candidate, CandidateModifier, NamedUtilityValue } from './candidate' -import type { Theme, ThemeKey } from './theme' +import { ThemeOptions, type Theme, type ThemeKey } from './theme' import { DefaultMap } from './utils/default-map' import { inferDataType, isPositiveInteger, isValidSpacingMultiplier } from './utils/infer-data-type' import { replaceShadowColors } from './utils/replace-shadow-colors' @@ -28,7 +28,8 @@ type SuggestionDefinition = { } export type UtilityOptions = { - types: string[] + types?: string[] + deprecated?: boolean } export type Utility = { @@ -42,8 +43,8 @@ export class Utilities { private completions = new Map SuggestionGroup[]>() - static(name: string, compileFn: CompileFn<'static'>) { - this.utilities.get(name).push({ kind: 'static', compileFn }) + static(name: string, compileFn: CompileFn<'static'>, options?: UtilityOptions) { + this.utilities.get(name).push({ kind: 'static', compileFn, options }) } functional(name: string, compileFn: CompileFn<'functional'>, options?: UtilityOptions) { @@ -54,6 +55,10 @@ export class Utilities { return this.utilities.has(name) && this.utilities.get(name).some((fn) => fn.kind === kind) } + isDeprecated(name: string, kind: 'static' | 'functional') { + return this.utilities.get(name).some((fn) => fn.kind === kind && fn.options?.deprecated) + } + get(name: string) { return this.utilities.has(name) ? this.utilities.get(name) : [] } @@ -203,9 +208,9 @@ export function createUtilities(theme: Theme) { * Register list of suggestions for a class */ function suggest(classRoot: string, defns: () => SuggestionDefinition[]) { - function* resolve(themeKeys: ThemeKey[]) { + function* resolve(themeKeys: ThemeKey[]): Iterable<[string, ThemeOptions]> { for (let value of theme.keysInNamespaces(themeKeys)) { - yield value.replaceAll('_', '.') + yield [value.replaceAll('_', '.'), theme.getOptions(value)] } } @@ -213,22 +218,44 @@ export function createUtilities(theme: Theme) { let groups: SuggestionGroup[] = [] for (let defn of defns()) { - let values: (string | null)[] = [ - ...(defn.values ?? []), - ...resolve(defn.valueThemeKeys ?? []), - ] - let modifiers = [...(defn.modifiers ?? []), ...resolve(defn.modifierThemeKeys ?? [])] + let values: [string | null, boolean][] = [] + let modifiers: [string, boolean][] = [] + + for (let key of defn.values ?? []) { + values.push([key, false]) + } + + for (let [key, options] of resolve(defn.valueThemeKeys ?? [])) { + values.push([key, (options & ThemeOptions.DEPRECATED) === ThemeOptions.DEPRECATED]) + } + + for (let key of defn.modifiers ?? []) { + values.push([key, false]) + } + + for (let [key, options] of resolve(defn.modifierThemeKeys ?? [])) { + values.push([key, (options & ThemeOptions.DEPRECATED) === ThemeOptions.DEPRECATED]) + } if (defn.hasDefaultValue) { - values.unshift(null) + values.unshift([null, false]) } - groups.push({ - supportsNegative: defn.supportsNegative, - values, - modifiers, - deprecated: defn.deprecated ?? false, - }) + for (let valueIsDeprecated of [false, true]) { + for (let modifierIsDeprecated of [false, true]) { + let valueList = values.filter((v) => v[1] === valueIsDeprecated).map((v) => v[0]) + let modifierList = modifiers + .filter((v) => v[1] === modifierIsDeprecated) + .map((v) => v[0]) + + groups.push({ + supportsNegative: defn.supportsNegative, + values: valueList, + modifiers: modifierList, + deprecated: defn.deprecated ?? false, + }) + } + } } return groups @@ -238,14 +265,22 @@ export function createUtilities(theme: Theme) { /** * Register a static utility class like `justify-center`. */ - function staticUtility(className: string, declarations: ([string, string] | (() => AstNode))[]) { - utilities.static(className, (candidate) => { - if (candidate.negative) return + function staticUtility( + className: string, + declarations: ([string, string] | (() => AstNode))[], + options?: UtilityOptions, + ) { + utilities.static( + className, + (candidate) => { + if (candidate.negative) return - return declarations.map((node) => { - return typeof node === 'function' ? node() : decl(node[0], node[1]) - }) - }) + return declarations.map((node) => { + return typeof node === 'function' ? node() : decl(node[0], node[1]) + }) + }, + options, + ) } type UtilityDescription = { @@ -256,6 +291,7 @@ export function createUtilities(theme: Theme) { handleBareValue?: (value: NamedUtilityValue) => string | null handleNegativeBareValue?: (value: NamedUtilityValue) => string | null handle: (value: string) => AstNode[] | undefined + deprecated?: boolean } /** @@ -263,59 +299,65 @@ export function createUtilities(theme: Theme) { * user's theme. */ function functionalUtility(classRoot: string, desc: UtilityDescription) { - utilities.functional(classRoot, (candidate) => { - // If the class candidate has a negative prefix (like `-mx-2`) but this - // utility doesn't support negative values (like the `width` utility), - // don't generate any rules. - if (candidate.negative && !desc.supportsNegative) return + utilities.functional( + classRoot, + (candidate) => { + // If the class candidate has a negative prefix (like `-mx-2`) but this + // utility doesn't support negative values (like the `width` utility), + // don't generate any rules. + if (candidate.negative && !desc.supportsNegative) return - let value: string | null = null + let value: string | null = null - if (!candidate.value) { - if (candidate.modifier) return + if (!candidate.value) { + if (candidate.modifier) return - // If the candidate has no value segment (like `rounded`), use the - // `defaultValue` (for candidates like `grow` that have no theme values) - // or a bare theme value (like `--radius` for `rounded`). No utility - // will ever support both of these. - value = desc.defaultValue ?? theme.resolve(null, desc.themeKeys ?? []) - } else if (candidate.value.kind === 'arbitrary') { - if (candidate.modifier) return - value = candidate.value.value - } else { - value = theme.resolve( - candidate.value.fraction ?? candidate.value.value, - desc.themeKeys ?? [], - ) - - // Automatically handle things like `w-1/2` without requiring `1/2` to - // exist as a theme value. - if (value === null && desc.supportsFractions && candidate.value.fraction) { - let [lhs, rhs] = segment(candidate.value.fraction, '/') - if (!isPositiveInteger(lhs) || !isPositiveInteger(rhs)) return - value = `calc(${candidate.value.fraction} * 100%)` - } + // If the candidate has no value segment (like `rounded`), use the + // `defaultValue` (for candidates like `grow` that have no theme values) + // or a bare theme value (like `--radius` for `rounded`). No utility + // will ever support both of these. + value = desc.defaultValue ?? theme.resolve(null, desc.themeKeys ?? []) + } else if (candidate.value.kind === 'arbitrary') { + if (candidate.modifier) return + value = candidate.value.value + } else { + value = theme.resolve( + candidate.value.fraction ?? candidate.value.value, + desc.themeKeys ?? [], + ) + + // Automatically handle things like `w-1/2` without requiring `1/2` to + // exist as a theme value. + if (value === null && desc.supportsFractions && candidate.value.fraction) { + let [lhs, rhs] = segment(candidate.value.fraction, '/') + if (!isPositiveInteger(lhs) || !isPositiveInteger(rhs)) return + value = `calc(${candidate.value.fraction} * 100%)` + } - // If there is still no value but the utility supports bare values, then - // use the bare candidate value as the value. - if (value === null && candidate.negative && desc.handleNegativeBareValue) { - value = desc.handleNegativeBareValue(candidate.value) - if (!value?.includes('/') && candidate.modifier) return - if (value !== null) return desc.handle(value) - } + // If there is still no value but the utility supports bare values, then + // use the bare candidate value as the value. + if (value === null && candidate.negative && desc.handleNegativeBareValue) { + value = desc.handleNegativeBareValue(candidate.value) + if (!value?.includes('/') && candidate.modifier) return + if (value !== null) return desc.handle(value) + } - if (value === null && desc.handleBareValue) { - value = desc.handleBareValue(candidate.value) - if (!value?.includes('/') && candidate.modifier) return + if (value === null && desc.handleBareValue) { + value = desc.handleBareValue(candidate.value) + if (!value?.includes('/') && candidate.modifier) return + } } - } - // If there is no value, don't generate any rules. - if (value === null) return + // If there is no value, don't generate any rules. + if (value === null) return - // Negate the value if the candidate has a negative prefix. - return desc.handle(withNegative(value, candidate)) - }) + // Negate the value if the candidate has a negative prefix. + return desc.handle(withNegative(value, candidate)) + }, + { + deprecated: desc.deprecated, + }, + ) suggest(classRoot, () => [ { @@ -1956,24 +1998,18 @@ export function createUtilities(theme: Theme) { staticUtility( `${root}-none`, properties.map((property) => [property, '0']), + { deprecated: true }, ) staticUtility( `${root}-full`, properties.map((property) => [property, 'calc(infinity * 1px)']), + { deprecated: true }, ) functionalUtility(root, { + deprecated: true, themeKeys: ['--radius', '--rounded'], handle: (value) => properties.map((property) => decl(property, value)), }) - - suggest(`${root}-none`, () => [{ deprecated: true }]) - suggest(`${root}-full`, () => [{ deprecated: true }]) - suggest(root, () => [ - { - valueThemeKeys: ['--radius'], - deprecated: true, - }, - ]) } // `radius-*` utilities From 44ff8e9661bc9f42e6ba0ee78f527e6e116b5d5b Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 8 Nov 2024 08:39:25 -0500 Subject: [PATCH 8/8] wip --- packages/tailwindcss/src/intellisense.test.ts | 20 ++++++++++++++++++- packages/tailwindcss/src/theme.ts | 6 +++--- packages/tailwindcss/src/utilities.ts | 9 ++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/tailwindcss/src/intellisense.test.ts b/packages/tailwindcss/src/intellisense.test.ts index 67ecca9747ff..6ae1d9370638 100644 --- a/packages/tailwindcss/src/intellisense.test.ts +++ b/packages/tailwindcss/src/intellisense.test.ts @@ -442,7 +442,7 @@ test('Custom at-rule variants do not show up as a value under `group`', async () expect(not.values).toContain('variant-4') }) -test.only('getClassMetadata(…)', async () => { +test('getClassMetadata(…)', async () => { let input = css` @tailwind utilities; ` @@ -456,3 +456,21 @@ test.only('getClassMetadata(…)', async () => { }, ]) }) + +test.only('Individual theme keys can be marked as deprecated', async () => { + let input = css` + @tailwind utilities; + @theme deprecated { + --shadow-sm: 0 0 0 rgba(0 0 0 / 0); + } + ` + + let design = await __unstable__loadDesignSystem(input) + + expect(design.classMetadata(['shadow-sm'])).toEqual([ + { + modifiers: [], + deprecated: true, + }, + ]) +}) diff --git a/packages/tailwindcss/src/theme.ts b/packages/tailwindcss/src/theme.ts index 71c450997653..0c0d56a0b8dd 100644 --- a/packages/tailwindcss/src/theme.ts +++ b/packages/tailwindcss/src/theme.ts @@ -69,8 +69,8 @@ export class Theme { } } - keysInNamespaces(themeKeys: ThemeKey[]): string[] { - let keys: string[] = [] + keysInNamespaces(themeKeys: ThemeKey[]): [string, string][] { + let keys: [string, string][] = [] for (let namespace of themeKeys) { let prefix = `${namespace}-` @@ -84,7 +84,7 @@ export class Theme { continue } - keys.push(key.slice(prefix.length)) + keys.push([key, key.slice(prefix.length)]) } } diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index c5a3fca2c366..bb3a6ca931b3 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -209,8 +209,8 @@ export function createUtilities(theme: Theme) { */ function suggest(classRoot: string, defns: () => SuggestionDefinition[]) { function* resolve(themeKeys: ThemeKey[]): Iterable<[string, ThemeOptions]> { - for (let value of theme.keysInNamespaces(themeKeys)) { - yield [value.replaceAll('_', '.'), theme.getOptions(value)] + for (let [themeKey, value] of theme.keysInNamespaces(themeKeys)) { + yield [value.replaceAll('_', '.'), theme.getOptions(themeKey)] } } @@ -220,6 +220,7 @@ export function createUtilities(theme: Theme) { for (let defn of defns()) { let values: [string | null, boolean][] = [] let modifiers: [string, boolean][] = [] + let isDeprecated = defn.deprecated ?? false for (let key of defn.values ?? []) { values.push([key, false]) @@ -248,11 +249,13 @@ export function createUtilities(theme: Theme) { .filter((v) => v[1] === modifierIsDeprecated) .map((v) => v[0]) + if (valueList.length === 0) continue + groups.push({ supportsNegative: defn.supportsNegative, values: valueList, modifiers: modifierList, - deprecated: defn.deprecated ?? false, + deprecated: isDeprecated || valueIsDeprecated || modifierIsDeprecated, }) } }