diff --git a/CHANGELOG.md b/CHANGELOG.md index 2afe7bcf2..50ab5fc24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Added + +- Add support for `addBase` plugins using the `@plugin` directive ([#14172](https://github.com/tailwindlabs/tailwindcss/pull/14172)) ## [4.0.0-alpha.19] - 2024-08-09 diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index fd855fffb..c92d6c2d2 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -2074,3 +2074,43 @@ describe('@variant', () => { `) }) }) + +test('addBase', async () => { + let { build } = await compile( + css` + @plugin "my-plugin"; + @layer base, utilities; + @layer utilities { + @tailwind utilities; + } + `, + + { + loadPlugin: async () => { + return ({ addBase }) => { + addBase({ + body: { + 'font-feature-settings': '"tnum"', + }, + }) + } + }, + }, + ) + + let compiled = build(['underline']) + + expect(optimizeCss(compiled).trim()).toMatchInlineSnapshot(` + "@layer base { + body { + font-feature-settings: "tnum"; + } + } + + @layer utilities { + .underline { + text-decoration-line: underline; + } + }" + `) +}) diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 803f0c2be..1a9f1feb5 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -281,7 +281,7 @@ async function parseCss(css: string, { loadPlugin = throwOnPlugin }: CompileOpti customUtility(designSystem) } - let pluginApi = buildPluginApi(designSystem) + let pluginApi = buildPluginApi(designSystem, ast) await Promise.all(pluginLoaders.map((loader) => loader.then((plugin) => plugin(pluginApi)))) diff --git a/packages/tailwindcss/src/plugin-api.ts b/packages/tailwindcss/src/plugin-api.ts index 66e07024f..6e9230af5 100644 --- a/packages/tailwindcss/src/plugin-api.ts +++ b/packages/tailwindcss/src/plugin-api.ts @@ -1,10 +1,11 @@ import { substituteAtApply } from './apply' -import { objectToAst, rule, type CssInJs } from './ast' +import { objectToAst, rule, type AstNode, type CssInJs } from './ast' import type { DesignSystem } from './design-system' import { withAlpha, withNegative } from './utilities' import { inferDataType } from './utils/infer-data-type' export type PluginAPI = { + addBase(base: CssInJs): void addVariant(name: string, variant: string | string[] | CssInJs): void addUtilities(utilities: Record, options?: {}): void matchUtilities( @@ -20,8 +21,12 @@ export type PluginAPI = { const IS_VALID_UTILITY_NAME = /^[a-z][a-zA-Z0-9/%._-]*$/ -export function buildPluginApi(designSystem: DesignSystem): PluginAPI { +export function buildPluginApi(designSystem: DesignSystem, ast: AstNode[]): PluginAPI { return { + addBase(css) { + ast.push(rule('@layer base', objectToAst(css))) + }, + addVariant(name, variant) { // Single selector if (typeof variant === 'string') {