diff --git a/packages/tailwindcss/src/compat/apply-compat-hooks.ts b/packages/tailwindcss/src/compat/apply-compat-hooks.ts index 964f78a96fec..e53a253ee8be 100644 --- a/packages/tailwindcss/src/compat/apply-compat-hooks.ts +++ b/packages/tailwindcss/src/compat/apply-compat-hooks.ts @@ -1,4 +1,4 @@ -import { decl, styleRule, toCss, walk, WalkAction, type AstNode } from '../ast' +import { styleRule, toCss, walk, WalkAction, type AstNode } from '../ast' import type { DesignSystem } from '../design-system' import { segment } from '../utils/segment' import { applyConfigToTheme } from './apply-config-to-theme' @@ -8,6 +8,7 @@ import { resolveConfig } from './config/resolve-config' import type { UserConfig } from './config/types' import { registerContainerCompat } from './container' import { darkModePlugin } from './dark-mode' +import { registerLegacyUtilities } from './legacy-utilities' import { buildPluginApi, type CssPluginOptions, type Plugin } from './plugin-api' import { registerScreensConfig } from './screens-config' import { registerThemeVariantOverrides } from './theme-variants' @@ -116,13 +117,7 @@ export async function applyCompatibilityHooks({ } }) - designSystem.utilities.functional('max-w-screen', (candidate) => { - if (!candidate.value) return - if (candidate.value.kind === 'arbitrary') return - let value = designSystem.theme.resolve(candidate.value.value, ['--breakpoint']) - if (!value) return - return [decl('max-width', value)] - }) + registerLegacyUtilities(designSystem) // Override `resolveThemeValue` with a version that is backwards compatible // with dot notation paths like `colors.red.500`. We could do this by default diff --git a/packages/tailwindcss/src/compat/legacy-utilities.test.ts b/packages/tailwindcss/src/compat/legacy-utilities.test.ts new file mode 100644 index 000000000000..d345cd865911 --- /dev/null +++ b/packages/tailwindcss/src/compat/legacy-utilities.test.ts @@ -0,0 +1,141 @@ +import { expect, test } from 'vitest' +import { compileCss, run } from '../test-utils/run' + +const css = String.raw + +test('bg-gradient-*', async () => { + expect( + await compileCss( + css` + @tailwind utilities; + `, + [ + 'bg-gradient-to-t', + 'bg-gradient-to-tr', + 'bg-gradient-to-r', + 'bg-gradient-to-br', + 'bg-gradient-to-b', + 'bg-gradient-to-bl', + 'bg-gradient-to-l', + 'bg-gradient-to-tl', + ], + ), + ).toMatchInlineSnapshot(` + ".bg-gradient-to-b { + --tw-gradient-position: to bottom in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-bl { + --tw-gradient-position: to bottom left in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-br { + --tw-gradient-position: to bottom right in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-l { + --tw-gradient-position: to left in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-r { + --tw-gradient-position: to right in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-t { + --tw-gradient-position: to top in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-tl { + --tw-gradient-position: to top left in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + } + + .bg-gradient-to-tr { + --tw-gradient-position: to top right in oklch, ; + background-image: linear-gradient(var(--tw-gradient-stops)); + background-image: linear-gradient(var(--tw-gradient-stops)); + }" + `) +}) + +test('max-w-screen', async () => { + expect( + await compileCss( + css` + @theme { + --breakpoint-sm: 40rem; + --breakpoint-md: 48rem; + --breakpoint-lg: 64rem; + --breakpoint-xl: 80rem; + --breakpoint-2xl: 96rem; + } + @tailwind utilities; + `, + [ + 'max-w-screen-sm', + 'max-w-screen-md', + 'max-w-screen-lg', + 'max-w-screen-xl', + 'max-w-screen-2xl', + ], + ), + ).toMatchInlineSnapshot(` + ":root { + --breakpoint-sm: 40rem; + --breakpoint-md: 48rem; + --breakpoint-lg: 64rem; + --breakpoint-xl: 80rem; + --breakpoint-2xl: 96rem; + } + + .max-w-screen-2xl { + max-width: var(--breakpoint-2xl); + } + + .max-w-screen-lg { + max-width: var(--breakpoint-lg); + } + + .max-w-screen-md { + max-width: var(--breakpoint-md); + } + + .max-w-screen-sm { + max-width: var(--breakpoint-sm); + } + + .max-w-screen-xl { + max-width: var(--breakpoint-xl); + }" + `) + expect( + await run([ + 'max-w-screen-oh', + 'max-w-screen-4', + 'max-w-screen-[4px]', + '-max-w-screen-sm', + '-max-w-screen-[4px]', + 'max-w-screen-none/foo', + 'max-w-screen-full/foo', + 'max-w-screen-max/foo', + 'max-w-screen-max/foo', + 'max-w-screen-fit/foo', + 'max-w-screen-4/foo', + 'max-w-screen-xl/foo', + 'max-w-screen-[4px]/foo', + ]), + ).toEqual('') +}) diff --git a/packages/tailwindcss/src/compat/legacy-utilities.ts b/packages/tailwindcss/src/compat/legacy-utilities.ts new file mode 100644 index 000000000000..082aff0fb96f --- /dev/null +++ b/packages/tailwindcss/src/compat/legacy-utilities.ts @@ -0,0 +1,28 @@ +import { decl } from '../ast' +import type { DesignSystem } from '../design-system' + +export function registerLegacyUtilities(designSystem: DesignSystem) { + for (let [value, direction] of [ + ['t', 'top'], + ['tr', 'top right'], + ['r', 'right'], + ['br', 'bottom right'], + ['b', 'bottom'], + ['bl', 'bottom left'], + ['l', 'left'], + ['tl', 'top left'], + ]) { + designSystem.utilities.static(`bg-gradient-to-${value}`, () => [ + decl('--tw-gradient-position', `to ${direction} in oklch,`), + decl('background-image', `linear-gradient(var(--tw-gradient-stops))`), + ]) + } + + designSystem.utilities.functional('max-w-screen', (candidate) => { + if (!candidate.value) return + if (candidate.value.kind === 'arbitrary') return + let value = designSystem.theme.resolve(candidate.value.value, ['--breakpoint']) + if (!value) return + return [decl('max-width', value)] + }) +} diff --git a/packages/tailwindcss/src/utilities.test.ts b/packages/tailwindcss/src/utilities.test.ts index 1e5c781c5faa..31ced83087b4 100644 --- a/packages/tailwindcss/src/utilities.test.ts +++ b/packages/tailwindcss/src/utilities.test.ts @@ -10357,16 +10357,6 @@ test('bg', async () => { // background-image 'bg-none', - // Legacy linear-gradient API - 'bg-gradient-to-t', - 'bg-gradient-to-tr', - 'bg-gradient-to-r', - 'bg-gradient-to-br', - 'bg-gradient-to-b', - 'bg-gradient-to-bl', - 'bg-gradient-to-l', - 'bg-gradient-to-tl', - // Modern linear-gradient API 'bg-linear-to-t', 'bg-linear-to-tr', @@ -10622,46 +10612,6 @@ test('bg', async () => { background-image: conic-gradient(var(--tw-gradient-stops)); } - .bg-gradient-to-b { - --tw-gradient-position: to bottom in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-bl { - --tw-gradient-position: to bottom left in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-br { - --tw-gradient-position: to bottom right in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-l { - --tw-gradient-position: to left in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-r { - --tw-gradient-position: to right in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-t { - --tw-gradient-position: to top in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-tl { - --tw-gradient-position: to top left in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - - .bg-gradient-to-tr { - --tw-gradient-position: to top right in oklch, ; - background-image: linear-gradient(var(--tw-gradient-stops)); - } - .bg-linear-45 { --tw-gradient-position: 45deg in oklch, ; background-image: linear-gradient(var(--tw-gradient-stops)); diff --git a/playgrounds/vite/src/app.tsx b/playgrounds/vite/src/app.tsx index 4abc17cb52e1..4b0776c1fa34 100644 --- a/playgrounds/vite/src/app.tsx +++ b/playgrounds/vite/src/app.tsx @@ -1,6 +1,6 @@ export function App() { return ( -